obs-x264.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. /******************************************************************************
  2. Copyright (C) 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 <stdio.h>
  15. #include <string.h>
  16. #include <util/bmem.h>
  17. #include <util/dstr.h>
  18. #include <util/darray.h>
  19. #include <util/platform.h>
  20. #include <obs-module.h>
  21. #include <opts-parser.h>
  22. #ifndef _STDINT_H_INCLUDED
  23. #define _STDINT_H_INCLUDED
  24. #endif
  25. #include <x264.h>
  26. #define do_log(level, format, ...) \
  27. blog(level, "[x264 encoder] " format, ##__VA_ARGS__)
  28. #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
  29. #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
  30. #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
  31. //#define ENABLE_VFR
  32. /* ------------------------------------------------------------------------- */
  33. struct obs_x264 {
  34. obs_encoder_t *encoder;
  35. x264_param_t params;
  36. x264_t *context;
  37. DARRAY(uint8_t) packet_data;
  38. uint8_t *extra_data;
  39. uint8_t *sei;
  40. size_t extra_data_size;
  41. size_t sei_size;
  42. os_performance_token_t *performance_token;
  43. };
  44. /* ------------------------------------------------------------------------- */
  45. static const char *obs_x264_getname(void *unused)
  46. {
  47. UNUSED_PARAMETER(unused);
  48. return "x264";
  49. }
  50. static void obs_x264_stop(void *data);
  51. static void clear_data(struct obs_x264 *obsx264)
  52. {
  53. if (obsx264->context) {
  54. x264_encoder_close(obsx264->context);
  55. bfree(obsx264->sei);
  56. bfree(obsx264->extra_data);
  57. obsx264->context = NULL;
  58. obsx264->sei = NULL;
  59. obsx264->extra_data = NULL;
  60. }
  61. }
  62. static void obs_x264_destroy(void *data)
  63. {
  64. struct obs_x264 *obsx264 = data;
  65. if (obsx264) {
  66. os_end_high_performance(obsx264->performance_token);
  67. clear_data(obsx264);
  68. da_free(obsx264->packet_data);
  69. bfree(obsx264);
  70. }
  71. }
  72. static void obs_x264_defaults(obs_data_t *settings)
  73. {
  74. obs_data_set_default_int(settings, "bitrate", 2500);
  75. obs_data_set_default_bool(settings, "use_bufsize", false);
  76. obs_data_set_default_int(settings, "buffer_size", 2500);
  77. obs_data_set_default_int(settings, "keyint_sec", 0);
  78. obs_data_set_default_int(settings, "crf", 23);
  79. #ifdef ENABLE_VFR
  80. obs_data_set_default_bool(settings, "vfr", false);
  81. #endif
  82. obs_data_set_default_string(settings, "rate_control", "CBR");
  83. obs_data_set_default_string(settings, "preset", "veryfast");
  84. obs_data_set_default_string(settings, "profile", "");
  85. obs_data_set_default_string(settings, "tune", "");
  86. obs_data_set_default_string(settings, "x264opts", "");
  87. obs_data_set_default_bool(settings, "repeat_headers", false);
  88. }
  89. static inline void add_strings(obs_property_t *list, const char *const *strings)
  90. {
  91. while (*strings) {
  92. obs_property_list_add_string(list, *strings, *strings);
  93. strings++;
  94. }
  95. }
  96. #define TEXT_RATE_CONTROL obs_module_text("RateControl")
  97. #define TEXT_BITRATE obs_module_text("Bitrate")
  98. #define TEXT_CUSTOM_BUF obs_module_text("CustomBufsize")
  99. #define TEXT_BUF_SIZE obs_module_text("BufferSize")
  100. #define TEXT_VFR obs_module_text("VFR")
  101. #define TEXT_CRF obs_module_text("CRF")
  102. #define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
  103. #define TEXT_PRESET obs_module_text("CPUPreset")
  104. #define TEXT_PROFILE obs_module_text("Profile")
  105. #define TEXT_TUNE obs_module_text("Tune")
  106. #define TEXT_NONE obs_module_text("None")
  107. #define TEXT_X264_OPTS obs_module_text("EncoderOptions")
  108. static bool use_bufsize_modified(obs_properties_t *ppts, obs_property_t *p,
  109. obs_data_t *settings)
  110. {
  111. bool use_bufsize = obs_data_get_bool(settings, "use_bufsize");
  112. const char *rc = obs_data_get_string(settings, "rate_control");
  113. bool rc_crf = astrcmpi(rc, "CRF") == 0;
  114. p = obs_properties_get(ppts, "buffer_size");
  115. obs_property_set_visible(p, use_bufsize && !rc_crf);
  116. return true;
  117. }
  118. static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
  119. obs_data_t *settings)
  120. {
  121. const char *rc = obs_data_get_string(settings, "rate_control");
  122. bool use_bufsize = obs_data_get_bool(settings, "use_bufsize");
  123. bool abr = astrcmpi(rc, "CBR") == 0 || astrcmpi(rc, "ABR") == 0;
  124. bool rc_crf = astrcmpi(rc, "CRF") == 0;
  125. p = obs_properties_get(ppts, "crf");
  126. obs_property_set_visible(p, !abr);
  127. p = obs_properties_get(ppts, "bitrate");
  128. obs_property_set_visible(p, !rc_crf);
  129. p = obs_properties_get(ppts, "use_bufsize");
  130. obs_property_set_visible(p, !rc_crf);
  131. p = obs_properties_get(ppts, "buffer_size");
  132. obs_property_set_visible(p, !rc_crf && use_bufsize);
  133. return true;
  134. }
  135. static obs_properties_t *obs_x264_props(void *unused)
  136. {
  137. UNUSED_PARAMETER(unused);
  138. obs_properties_t *props = obs_properties_create();
  139. obs_property_t *list;
  140. obs_property_t *p;
  141. obs_property_t *headers;
  142. list = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL,
  143. OBS_COMBO_TYPE_LIST,
  144. OBS_COMBO_FORMAT_STRING);
  145. obs_property_list_add_string(list, "CBR", "CBR");
  146. obs_property_list_add_string(list, "ABR", "ABR");
  147. obs_property_list_add_string(list, "VBR", "VBR");
  148. obs_property_list_add_string(list, "CRF", "CRF");
  149. obs_property_set_modified_callback(list, rate_control_modified);
  150. p = obs_properties_add_int(props, "bitrate", TEXT_BITRATE, 50, 10000000,
  151. 50);
  152. obs_property_int_set_suffix(p, " Kbps");
  153. p = obs_properties_add_bool(props, "use_bufsize", TEXT_CUSTOM_BUF);
  154. obs_property_set_modified_callback(p, use_bufsize_modified);
  155. obs_properties_add_int(props, "buffer_size", TEXT_BUF_SIZE, 0, 10000000,
  156. 1);
  157. obs_properties_add_int(props, "crf", TEXT_CRF, 0, 51, 1);
  158. obs_properties_add_int(props, "keyint_sec", TEXT_KEYINT_SEC, 0, 20, 1);
  159. list = obs_properties_add_list(props, "preset", TEXT_PRESET,
  160. OBS_COMBO_TYPE_LIST,
  161. OBS_COMBO_FORMAT_STRING);
  162. add_strings(list, x264_preset_names);
  163. list = obs_properties_add_list(props, "profile", TEXT_PROFILE,
  164. OBS_COMBO_TYPE_LIST,
  165. OBS_COMBO_FORMAT_STRING);
  166. obs_property_list_add_string(list, TEXT_NONE, "");
  167. obs_property_list_add_string(list, "baseline", "baseline");
  168. obs_property_list_add_string(list, "main", "main");
  169. obs_property_list_add_string(list, "high", "high");
  170. list = obs_properties_add_list(props, "tune", TEXT_TUNE,
  171. OBS_COMBO_TYPE_LIST,
  172. OBS_COMBO_FORMAT_STRING);
  173. obs_property_list_add_string(list, TEXT_NONE, "");
  174. add_strings(list, x264_tune_names);
  175. #ifdef ENABLE_VFR
  176. obs_properties_add_bool(props, "vfr", TEXT_VFR);
  177. #endif
  178. obs_properties_add_text(props, "x264opts", TEXT_X264_OPTS,
  179. OBS_TEXT_DEFAULT);
  180. headers = obs_properties_add_bool(props, "repeat_headers",
  181. "repeat_headers");
  182. obs_property_set_visible(headers, false);
  183. return props;
  184. }
  185. static bool getparam(const char *param, char **name, const char **value)
  186. {
  187. const char *assign;
  188. if (!param || !*param || (*param == '='))
  189. return false;
  190. assign = strchr(param, '=');
  191. if (!assign || !*assign || !*(assign + 1))
  192. return false;
  193. *name = bstrdup_n(param, assign - param);
  194. *value = assign + 1;
  195. return true;
  196. }
  197. static const char *validate(struct obs_x264 *obsx264, const char *val,
  198. const char *name, const char *const *list)
  199. {
  200. if (!val || !*val)
  201. return val;
  202. while (*list) {
  203. if (strcmp(val, *list) == 0)
  204. return val;
  205. list++;
  206. }
  207. warn("Invalid %s: %s", name, val);
  208. return NULL;
  209. }
  210. static void override_base_param(struct obs_x264 *obsx264,
  211. struct obs_option option, char **preset,
  212. char **profile, char **tune)
  213. {
  214. const char *name = option.name;
  215. const char *val = option.value;
  216. if (astrcmpi(name, "preset") == 0) {
  217. const char *valid_name =
  218. validate(obsx264, val, "preset", x264_preset_names);
  219. if (valid_name) {
  220. bfree(*preset);
  221. *preset = bstrdup(val);
  222. }
  223. } else if (astrcmpi(name, "profile") == 0) {
  224. const char *valid_name =
  225. validate(obsx264, val, "profile", x264_profile_names);
  226. if (valid_name) {
  227. bfree(*profile);
  228. *profile = bstrdup(val);
  229. }
  230. } else if (astrcmpi(name, "tune") == 0) {
  231. const char *valid_name =
  232. validate(obsx264, val, "tune", x264_tune_names);
  233. if (valid_name) {
  234. bfree(*tune);
  235. *tune = bstrdup(val);
  236. }
  237. }
  238. }
  239. static inline void override_base_params(struct obs_x264 *obsx264,
  240. const struct obs_options *options,
  241. char **preset, char **profile,
  242. char **tune)
  243. {
  244. for (size_t i = 0; i < options->count; ++i)
  245. override_base_param(obsx264, options->options[i], preset,
  246. profile, tune);
  247. }
  248. #define OPENCL_ALIAS "opencl_is_experimental_and_potentially_unstable"
  249. static inline void set_param(struct obs_x264 *obsx264, struct obs_option option)
  250. {
  251. const char *name = option.name;
  252. const char *val = option.value;
  253. if (strcmp(name, "preset") != 0 && strcmp(name, "profile") != 0 &&
  254. strcmp(name, "tune") != 0 && strcmp(name, "fps") != 0 &&
  255. strcmp(name, "force-cfr") != 0 && strcmp(name, "width") != 0 &&
  256. strcmp(name, "height") != 0 && strcmp(name, "opencl") != 0) {
  257. if (strcmp(option.name, OPENCL_ALIAS) == 0)
  258. name = "opencl";
  259. if (x264_param_parse(&obsx264->params, name, val) != 0)
  260. warn("x264 param: %s=%s failed", name, val);
  261. }
  262. }
  263. static inline void apply_x264_profile(struct obs_x264 *obsx264,
  264. const char *profile)
  265. {
  266. if (!obsx264->context && profile && *profile) {
  267. int ret = x264_param_apply_profile(&obsx264->params, profile);
  268. if (ret != 0)
  269. warn("Failed to set x264 profile '%s'", profile);
  270. }
  271. }
  272. static inline const char *validate_preset(struct obs_x264 *obsx264,
  273. const char *preset)
  274. {
  275. const char *new_preset =
  276. validate(obsx264, preset, "preset", x264_preset_names);
  277. return new_preset ? new_preset : "veryfast";
  278. }
  279. static bool reset_x264_params(struct obs_x264 *obsx264, const char *preset,
  280. const char *tune)
  281. {
  282. int ret = x264_param_default_preset(
  283. &obsx264->params, validate_preset(obsx264, preset),
  284. validate(obsx264, tune, "tune", x264_tune_names));
  285. return ret == 0;
  286. }
  287. static void log_x264(void *param, int level, const char *format, va_list args)
  288. {
  289. struct obs_x264 *obsx264 = param;
  290. char str[1024];
  291. vsnprintf(str, 1024, format, args);
  292. info("%s", str);
  293. UNUSED_PARAMETER(level);
  294. }
  295. static inline int get_x264_cs_val(const char *const name,
  296. const char *const names[])
  297. {
  298. int idx = 0;
  299. do {
  300. if (strcmp(names[idx], name) == 0)
  301. return idx;
  302. } while (!!names[++idx]);
  303. return 0;
  304. }
  305. static void obs_x264_video_info(void *data, struct video_scale_info *info);
  306. enum rate_control {
  307. RATE_CONTROL_CBR,
  308. RATE_CONTROL_VBR,
  309. RATE_CONTROL_ABR,
  310. RATE_CONTROL_CRF
  311. };
  312. static void update_params(struct obs_x264 *obsx264, obs_data_t *settings,
  313. const struct obs_options *options, bool update)
  314. {
  315. video_t *video = obs_encoder_video(obsx264->encoder);
  316. const struct video_output_info *voi = video_output_get_info(video);
  317. struct video_scale_info info;
  318. info.format = voi->format;
  319. info.colorspace = voi->colorspace;
  320. info.range = voi->range;
  321. obs_x264_video_info(obsx264, &info);
  322. const char *rate_control =
  323. obs_data_get_string(settings, "rate_control");
  324. int bitrate = (int)obs_data_get_int(settings, "bitrate");
  325. int buffer_size = (int)obs_data_get_int(settings, "buffer_size");
  326. int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
  327. int crf = (int)obs_data_get_int(settings, "crf");
  328. int width = (int)obs_encoder_get_width(obsx264->encoder);
  329. int height = (int)obs_encoder_get_height(obsx264->encoder);
  330. int bf = (int)obs_data_get_int(settings, "bf");
  331. bool use_bufsize = obs_data_get_bool(settings, "use_bufsize");
  332. bool cbr_override = obs_data_get_bool(settings, "cbr");
  333. enum rate_control rc;
  334. #ifdef ENABLE_VFR
  335. bool vfr = obs_data_get_bool(settings, "vfr");
  336. #endif
  337. /* XXX: "cbr" setting has been deprecated */
  338. if (cbr_override) {
  339. warn("\"cbr\" setting has been deprecated for all encoders! "
  340. "Please set \"rate_control\" to \"CBR\" instead. "
  341. "Forcing CBR mode. "
  342. "(Note to all: this is why you shouldn't use strings for "
  343. "common settings)");
  344. rate_control = "CBR";
  345. }
  346. if (astrcmpi(rate_control, "ABR") == 0) {
  347. rc = RATE_CONTROL_ABR;
  348. crf = 0;
  349. } else if (astrcmpi(rate_control, "VBR") == 0) {
  350. rc = RATE_CONTROL_VBR;
  351. } else if (astrcmpi(rate_control, "CRF") == 0) {
  352. rc = RATE_CONTROL_CRF;
  353. bitrate = 0;
  354. buffer_size = 0;
  355. } else { /* CBR */
  356. rc = RATE_CONTROL_CBR;
  357. crf = 0;
  358. }
  359. if (keyint_sec)
  360. obsx264->params.i_keyint_max =
  361. keyint_sec * voi->fps_num / voi->fps_den;
  362. if (!use_bufsize)
  363. buffer_size = bitrate;
  364. #ifdef ENABLE_VFR
  365. obsx264->params.b_vfr_input = vfr;
  366. #else
  367. obsx264->params.b_vfr_input = false;
  368. #endif
  369. obsx264->params.rc.i_vbv_max_bitrate = bitrate;
  370. obsx264->params.rc.i_vbv_buffer_size = buffer_size;
  371. obsx264->params.rc.i_bitrate = bitrate;
  372. obsx264->params.i_width = width;
  373. obsx264->params.i_height = height;
  374. obsx264->params.i_fps_num = voi->fps_num;
  375. obsx264->params.i_fps_den = voi->fps_den;
  376. obsx264->params.i_timebase_num = voi->fps_den;
  377. obsx264->params.i_timebase_den = voi->fps_num;
  378. obsx264->params.pf_log = log_x264;
  379. obsx264->params.p_log_private = obsx264;
  380. obsx264->params.i_log_level = X264_LOG_WARNING;
  381. if (obs_data_has_user_value(settings, "bf"))
  382. obsx264->params.i_bframe = bf;
  383. static const char *const smpte170m = "smpte170m";
  384. static const char *const bt709 = "bt709";
  385. static const char *const bt2020 = "bt2020";
  386. static const char *const bt2020nc = "bt2020nc";
  387. const char *colorprim = bt709;
  388. const char *transfer = bt709;
  389. const char *colmatrix = bt709;
  390. switch (info.colorspace) {
  391. case VIDEO_CS_DEFAULT:
  392. case VIDEO_CS_709:
  393. colorprim = bt709;
  394. transfer = bt709;
  395. colmatrix = bt709;
  396. break;
  397. case VIDEO_CS_601:
  398. colorprim = smpte170m;
  399. transfer = smpte170m;
  400. colmatrix = smpte170m;
  401. break;
  402. case VIDEO_CS_SRGB:
  403. colorprim = bt709;
  404. transfer = "iec61966-2-1";
  405. colmatrix = bt709;
  406. break;
  407. case VIDEO_CS_2100_PQ:
  408. colorprim = bt2020;
  409. transfer = "smpte2084";
  410. colmatrix = bt2020nc;
  411. break;
  412. case VIDEO_CS_2100_HLG:
  413. colorprim = bt2020;
  414. transfer = "arib-std-b67";
  415. colmatrix = bt2020nc;
  416. }
  417. obsx264->params.vui.i_sar_height = 1;
  418. obsx264->params.vui.i_sar_width = 1;
  419. obsx264->params.vui.b_fullrange = info.range == VIDEO_RANGE_FULL;
  420. obsx264->params.vui.i_colorprim =
  421. get_x264_cs_val(colorprim, x264_colorprim_names);
  422. obsx264->params.vui.i_transfer =
  423. get_x264_cs_val(transfer, x264_transfer_names);
  424. obsx264->params.vui.i_colmatrix =
  425. get_x264_cs_val(colmatrix, x264_colmatrix_names);
  426. /* use the new filler method for CBR to allow real-time adjusting of
  427. * the bitrate */
  428. if (rc == RATE_CONTROL_CBR || rc == RATE_CONTROL_ABR) {
  429. obsx264->params.rc.i_rc_method = X264_RC_ABR;
  430. if (rc == RATE_CONTROL_CBR) {
  431. #if X264_BUILD >= 139
  432. obsx264->params.rc.b_filler = true;
  433. #else
  434. obsx264->params.i_nal_hrd = X264_NAL_HRD_CBR;
  435. #endif
  436. }
  437. } else {
  438. obsx264->params.rc.i_rc_method = X264_RC_CRF;
  439. obsx264->params.rc.f_rf_constant = (float)crf;
  440. }
  441. if (info.format == VIDEO_FORMAT_NV12)
  442. obsx264->params.i_csp = X264_CSP_NV12;
  443. else if (info.format == VIDEO_FORMAT_I420)
  444. obsx264->params.i_csp = X264_CSP_I420;
  445. else if (info.format == VIDEO_FORMAT_I444)
  446. obsx264->params.i_csp = X264_CSP_I444;
  447. else
  448. obsx264->params.i_csp = X264_CSP_NV12;
  449. for (size_t i = 0; i < options->ignored_word_count; ++i)
  450. warn("ignoring invalid x264 option: %s",
  451. options->ignored_words[i]);
  452. for (size_t i = 0; i < options->count; ++i)
  453. set_param(obsx264, options->options[i]);
  454. if (!update) {
  455. info("settings:\n"
  456. "\trate_control: %s\n"
  457. "\tbitrate: %d\n"
  458. "\tbuffer size: %d\n"
  459. "\tcrf: %d\n"
  460. "\tfps_num: %d\n"
  461. "\tfps_den: %d\n"
  462. "\twidth: %d\n"
  463. "\theight: %d\n"
  464. "\tkeyint: %d\n",
  465. rate_control, obsx264->params.rc.i_vbv_max_bitrate,
  466. obsx264->params.rc.i_vbv_buffer_size,
  467. (int)obsx264->params.rc.f_rf_constant, voi->fps_num,
  468. voi->fps_den, width, height, obsx264->params.i_keyint_max);
  469. }
  470. }
  471. static void log_custom_options(struct obs_x264 *obsx264,
  472. const struct obs_options *options)
  473. {
  474. if (options->count == 0) {
  475. return;
  476. }
  477. size_t settings_string_length = 0;
  478. for (size_t i = 0; i < options->count; ++i)
  479. settings_string_length += strlen(options->options[i].name) +
  480. strlen(options->options[i].value) + 5;
  481. size_t buffer_size = settings_string_length + 1;
  482. char *settings_string = bmalloc(settings_string_length + 1);
  483. char *p = settings_string;
  484. size_t remaining_buffer_size = buffer_size;
  485. for (size_t i = 0; i < options->count; ++i) {
  486. int chars_written = snprintf(p, remaining_buffer_size,
  487. "\n\t%s = %s",
  488. options->options[i].name,
  489. options->options[i].value);
  490. assert(chars_written >= 0);
  491. assert((size_t)chars_written <= remaining_buffer_size);
  492. p += chars_written;
  493. remaining_buffer_size -= chars_written;
  494. }
  495. assert(remaining_buffer_size == 1);
  496. assert(*p == '\0');
  497. info("custom settings: %s", settings_string);
  498. bfree(settings_string);
  499. }
  500. static bool update_settings(struct obs_x264 *obsx264, obs_data_t *settings,
  501. bool update)
  502. {
  503. char *preset = bstrdup(obs_data_get_string(settings, "preset"));
  504. char *profile = bstrdup(obs_data_get_string(settings, "profile"));
  505. char *tune = bstrdup(obs_data_get_string(settings, "tune"));
  506. struct obs_options options =
  507. obs_parse_options(obs_data_get_string(settings, "x264opts"));
  508. bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
  509. bool success = true;
  510. if (!update)
  511. blog(LOG_INFO, "---------------------------------");
  512. if (!obsx264->context) {
  513. override_base_params(obsx264, &options, &preset, &profile,
  514. &tune);
  515. if (preset && *preset)
  516. info("preset: %s", preset);
  517. if (profile && *profile)
  518. info("profile: %s", profile);
  519. if (tune && *tune)
  520. info("tune: %s", tune);
  521. success = reset_x264_params(obsx264, preset, tune);
  522. }
  523. if (repeat_headers) {
  524. obsx264->params.b_repeat_headers = 1;
  525. obsx264->params.b_annexb = 1;
  526. obsx264->params.b_aud = 1;
  527. }
  528. if (success) {
  529. update_params(obsx264, settings, &options, update);
  530. if (!update) {
  531. log_custom_options(obsx264, &options);
  532. }
  533. if (!obsx264->context)
  534. apply_x264_profile(obsx264, profile);
  535. }
  536. obs_free_options(options);
  537. bfree(preset);
  538. bfree(profile);
  539. bfree(tune);
  540. return success;
  541. }
  542. static bool obs_x264_update(void *data, obs_data_t *settings)
  543. {
  544. struct obs_x264 *obsx264 = data;
  545. bool success = update_settings(obsx264, settings, true);
  546. int ret;
  547. if (success) {
  548. ret = x264_encoder_reconfig(obsx264->context, &obsx264->params);
  549. if (ret != 0)
  550. warn("Failed to reconfigure: %d", ret);
  551. return ret == 0;
  552. }
  553. return false;
  554. }
  555. static void load_headers(struct obs_x264 *obsx264)
  556. {
  557. x264_nal_t *nals;
  558. int nal_count;
  559. DARRAY(uint8_t) header;
  560. DARRAY(uint8_t) sei;
  561. da_init(header);
  562. da_init(sei);
  563. x264_encoder_headers(obsx264->context, &nals, &nal_count);
  564. for (int i = 0; i < nal_count; i++) {
  565. x264_nal_t *nal = nals + i;
  566. if (nal->i_type == NAL_SEI)
  567. da_push_back_array(sei, nal->p_payload, nal->i_payload);
  568. else
  569. da_push_back_array(header, nal->p_payload,
  570. nal->i_payload);
  571. }
  572. obsx264->extra_data = header.array;
  573. obsx264->extra_data_size = header.num;
  574. obsx264->sei = sei.array;
  575. obsx264->sei_size = sei.num;
  576. }
  577. static void *obs_x264_create(obs_data_t *settings, obs_encoder_t *encoder)
  578. {
  579. video_t *video = obs_encoder_video(encoder);
  580. const struct video_output_info *voi = video_output_get_info(video);
  581. switch (voi->colorspace) {
  582. case VIDEO_CS_2100_PQ:
  583. case VIDEO_CS_2100_HLG:
  584. warn("OBS does not support using x264 with Rec. 2100");
  585. return NULL;
  586. }
  587. struct obs_x264 *obsx264 = bzalloc(sizeof(struct obs_x264));
  588. obsx264->encoder = encoder;
  589. if (update_settings(obsx264, settings, false)) {
  590. obsx264->context = x264_encoder_open(&obsx264->params);
  591. if (obsx264->context == NULL)
  592. warn("x264 failed to load");
  593. else
  594. load_headers(obsx264);
  595. } else {
  596. warn("bad settings specified");
  597. }
  598. if (!obsx264->context) {
  599. bfree(obsx264);
  600. return NULL;
  601. }
  602. obsx264->performance_token =
  603. os_request_high_performance("x264 encoding");
  604. return obsx264;
  605. }
  606. static void parse_packet(struct obs_x264 *obsx264,
  607. struct encoder_packet *packet, x264_nal_t *nals,
  608. int nal_count, x264_picture_t *pic_out)
  609. {
  610. if (!nal_count)
  611. return;
  612. da_resize(obsx264->packet_data, 0);
  613. for (int i = 0; i < nal_count; i++) {
  614. x264_nal_t *nal = nals + i;
  615. da_push_back_array(obsx264->packet_data, nal->p_payload,
  616. nal->i_payload);
  617. }
  618. packet->data = obsx264->packet_data.array;
  619. packet->size = obsx264->packet_data.num;
  620. packet->type = OBS_ENCODER_VIDEO;
  621. packet->pts = pic_out->i_pts;
  622. packet->dts = pic_out->i_dts;
  623. packet->keyframe = pic_out->b_keyframe != 0;
  624. }
  625. static inline void init_pic_data(struct obs_x264 *obsx264, x264_picture_t *pic,
  626. struct encoder_frame *frame)
  627. {
  628. x264_picture_init(pic);
  629. pic->i_pts = frame->pts;
  630. pic->img.i_csp = obsx264->params.i_csp;
  631. if (obsx264->params.i_csp == X264_CSP_NV12)
  632. pic->img.i_plane = 2;
  633. else if (obsx264->params.i_csp == X264_CSP_I420)
  634. pic->img.i_plane = 3;
  635. else if (obsx264->params.i_csp == X264_CSP_I444)
  636. pic->img.i_plane = 3;
  637. for (int i = 0; i < pic->img.i_plane; i++) {
  638. pic->img.i_stride[i] = (int)frame->linesize[i];
  639. pic->img.plane[i] = frame->data[i];
  640. }
  641. }
  642. static bool obs_x264_encode(void *data, struct encoder_frame *frame,
  643. struct encoder_packet *packet,
  644. bool *received_packet)
  645. {
  646. struct obs_x264 *obsx264 = data;
  647. x264_nal_t *nals;
  648. int nal_count;
  649. int ret;
  650. x264_picture_t pic, pic_out;
  651. if (!frame || !packet || !received_packet)
  652. return false;
  653. if (frame)
  654. init_pic_data(obsx264, &pic, frame);
  655. ret = x264_encoder_encode(obsx264->context, &nals, &nal_count,
  656. (frame ? &pic : NULL), &pic_out);
  657. if (ret < 0) {
  658. warn("encode failed");
  659. return false;
  660. }
  661. *received_packet = (nal_count != 0);
  662. parse_packet(obsx264, packet, nals, nal_count, &pic_out);
  663. return true;
  664. }
  665. static bool obs_x264_extra_data(void *data, uint8_t **extra_data, size_t *size)
  666. {
  667. struct obs_x264 *obsx264 = data;
  668. if (!obsx264->context)
  669. return false;
  670. *extra_data = obsx264->extra_data;
  671. *size = obsx264->extra_data_size;
  672. return true;
  673. }
  674. static bool obs_x264_sei(void *data, uint8_t **sei, size_t *size)
  675. {
  676. struct obs_x264 *obsx264 = data;
  677. if (!obsx264->context)
  678. return false;
  679. *sei = obsx264->sei;
  680. *size = obsx264->sei_size;
  681. return true;
  682. }
  683. static inline bool valid_format(enum video_format format)
  684. {
  685. return format == VIDEO_FORMAT_I420 || format == VIDEO_FORMAT_NV12 ||
  686. format == VIDEO_FORMAT_I444;
  687. }
  688. static void obs_x264_video_info(void *data, struct video_scale_info *info)
  689. {
  690. struct obs_x264 *obsx264 = data;
  691. enum video_format pref_format;
  692. pref_format = obs_encoder_get_preferred_video_format(obsx264->encoder);
  693. if (!valid_format(pref_format)) {
  694. pref_format = valid_format(info->format) ? info->format
  695. : VIDEO_FORMAT_NV12;
  696. }
  697. info->format = pref_format;
  698. }
  699. struct obs_encoder_info obs_x264_encoder = {
  700. .id = "obs_x264",
  701. .type = OBS_ENCODER_VIDEO,
  702. .codec = "h264",
  703. .get_name = obs_x264_getname,
  704. .create = obs_x264_create,
  705. .destroy = obs_x264_destroy,
  706. .encode = obs_x264_encode,
  707. .update = obs_x264_update,
  708. .get_properties = obs_x264_props,
  709. .get_defaults = obs_x264_defaults,
  710. .get_extra_data = obs_x264_extra_data,
  711. .get_sei_data = obs_x264_sei,
  712. .get_video_info = obs_x264_video_info,
  713. .caps = OBS_ENCODER_CAP_DYN_BITRATE,
  714. };