nvenc-compat.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #include "nvenc-helpers.h"
  2. #include <util/dstr.h>
  3. /*
  4. * Compatibility encoder objects for pre-31.0 encoder compatibility.
  5. *
  6. * All they do is update the settings object, and then reroute to one of the
  7. * new encoder implementations.
  8. *
  9. * This should be removed once NVENC settings are migrated directly and
  10. * backwards-compatibility is no longer required.
  11. */
  12. /* ------------------------------------------------------------------------- */
  13. /* Actual redirector implementation. */
  14. static void migrate_settings(obs_data_t *settings)
  15. {
  16. const char *preset = obs_data_get_string(settings, "preset2");
  17. obs_data_set_string(settings, "preset", preset);
  18. obs_data_set_bool(settings, "adaptive_quantization",
  19. obs_data_get_bool(settings, "psycho_aq"));
  20. if (obs_data_has_user_value(settings, "gpu") &&
  21. num_encoder_devices() > 1) {
  22. obs_data_set_int(settings, "device",
  23. obs_data_get_int(settings, "gpu"));
  24. }
  25. }
  26. static void *nvenc_reroute(enum codec_type codec, obs_data_t *settings,
  27. obs_encoder_t *encoder, bool texture)
  28. {
  29. /* Update settings object to v2 encoder configuration */
  30. migrate_settings(settings);
  31. switch (codec) {
  32. case CODEC_H264:
  33. return obs_encoder_create_rerouted(
  34. encoder,
  35. texture ? "obs_nvenc_h264_tex" : "obs_nvenc_h264_soft");
  36. case CODEC_HEVC:
  37. return obs_encoder_create_rerouted(
  38. encoder,
  39. texture ? "obs_nvenc_hevc_tex" : "obs_nvenc_hevc_soft");
  40. case CODEC_AV1:
  41. return obs_encoder_create_rerouted(
  42. encoder,
  43. texture ? "obs_nvenc_av1_tex" : "obs_nvenc_av1_soft");
  44. }
  45. return NULL;
  46. }
  47. /* ------------------------------------------------------------------------- */
  48. static const char *h264_nvenc_get_name(void *type_data)
  49. {
  50. UNUSED_PARAMETER(type_data);
  51. return "NVIDIA NVENC H.264";
  52. }
  53. #ifdef ENABLE_HEVC
  54. static const char *hevc_nvenc_get_name(void *type_data)
  55. {
  56. UNUSED_PARAMETER(type_data);
  57. return "NVIDIA NVENC HEVC";
  58. }
  59. #endif
  60. static const char *av1_nvenc_get_name(void *type_data)
  61. {
  62. UNUSED_PARAMETER(type_data);
  63. return "NVIDIA NVENC AV1";
  64. }
  65. static void *h264_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
  66. {
  67. return nvenc_reroute(CODEC_H264, settings, encoder, true);
  68. }
  69. #ifdef ENABLE_HEVC
  70. static void *hevc_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
  71. {
  72. return nvenc_reroute(CODEC_HEVC, settings, encoder, true);
  73. }
  74. #endif
  75. static void *av1_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
  76. {
  77. return nvenc_reroute(CODEC_AV1, settings, encoder, true);
  78. }
  79. static void *h264_nvenc_soft_create(obs_data_t *settings,
  80. obs_encoder_t *encoder)
  81. {
  82. return nvenc_reroute(CODEC_H264, settings, encoder, false);
  83. }
  84. #ifdef ENABLE_HEVC
  85. static void *hevc_nvenc_soft_create(obs_data_t *settings,
  86. obs_encoder_t *encoder)
  87. {
  88. return nvenc_reroute(CODEC_HEVC, settings, encoder, false);
  89. }
  90. #endif
  91. static void *av1_nvenc_soft_create(obs_data_t *settings, obs_encoder_t *encoder)
  92. {
  93. return nvenc_reroute(CODEC_AV1, settings, encoder, false);
  94. }
  95. static void nvenc_defaults_base(enum codec_type codec, obs_data_t *settings)
  96. {
  97. /* Defaults from legacy FFmpeg encoder */
  98. obs_data_set_default_int(settings, "bitrate", 2500);
  99. obs_data_set_default_int(settings, "max_bitrate", 5000);
  100. obs_data_set_default_int(settings, "keyint_sec", 0);
  101. obs_data_set_default_int(settings, "cqp", 20);
  102. obs_data_set_default_string(settings, "rate_control", "CBR");
  103. obs_data_set_default_string(settings, "preset2", "p5");
  104. obs_data_set_default_string(settings, "multipass", "qres");
  105. obs_data_set_default_string(settings, "tune", "hq");
  106. obs_data_set_default_string(settings, "profile",
  107. codec != CODEC_H264 ? "main" : "high");
  108. obs_data_set_default_bool(settings, "psycho_aq", true);
  109. obs_data_set_default_int(settings, "gpu", 0);
  110. obs_data_set_default_int(settings, "bf", 2);
  111. obs_data_set_default_bool(settings, "repeat_headers", false);
  112. }
  113. static void h264_nvenc_defaults(obs_data_t *settings)
  114. {
  115. nvenc_defaults_base(CODEC_H264, settings);
  116. }
  117. #ifdef ENABLE_HEVC
  118. static void hevc_nvenc_defaults(obs_data_t *settings)
  119. {
  120. nvenc_defaults_base(CODEC_HEVC, settings);
  121. }
  122. #endif
  123. static void av1_nvenc_defaults(obs_data_t *settings)
  124. {
  125. nvenc_defaults_base(CODEC_AV1, settings);
  126. }
  127. static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
  128. obs_data_t *settings)
  129. {
  130. const char *rc = obs_data_get_string(settings, "rate_control");
  131. bool cqp = astrcmpi(rc, "CQP") == 0;
  132. bool vbr = astrcmpi(rc, "VBR") == 0;
  133. bool lossless = astrcmpi(rc, "lossless") == 0;
  134. p = obs_properties_get(ppts, "bitrate");
  135. obs_property_set_visible(p, !cqp && !lossless);
  136. p = obs_properties_get(ppts, "max_bitrate");
  137. obs_property_set_visible(p, vbr);
  138. p = obs_properties_get(ppts, "cqp");
  139. obs_property_set_visible(p, cqp);
  140. p = obs_properties_get(ppts, "preset2");
  141. obs_property_set_visible(p, !lossless);
  142. p = obs_properties_get(ppts, "tune");
  143. obs_property_set_visible(p, !lossless);
  144. return true;
  145. }
  146. static obs_properties_t *nvenc_properties_internal(enum codec_type codec)
  147. {
  148. obs_properties_t *props = obs_properties_create();
  149. obs_property_t *p;
  150. p = obs_properties_add_list(props, "rate_control",
  151. obs_module_text("RateControl"),
  152. OBS_COMBO_TYPE_LIST,
  153. OBS_COMBO_FORMAT_STRING);
  154. obs_property_list_add_string(p, "CBR", "CBR");
  155. obs_property_list_add_string(p, "CQP", "CQP");
  156. obs_property_list_add_string(p, "VBR", "VBR");
  157. obs_property_list_add_string(p, obs_module_text("Lossless"),
  158. "lossless");
  159. obs_property_set_modified_callback(p, rate_control_modified);
  160. p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"),
  161. 50, 300000, 50);
  162. obs_property_int_set_suffix(p, " Kbps");
  163. p = obs_properties_add_int(props, "max_bitrate",
  164. obs_module_text("MaxBitrate"), 50, 300000,
  165. 50);
  166. obs_property_int_set_suffix(p, " Kbps");
  167. obs_properties_add_int(props, "cqp", obs_module_text("CQLevel"), 1,
  168. codec == CODEC_AV1 ? 63 : 51, 1);
  169. p = obs_properties_add_int(props, "keyint_sec",
  170. obs_module_text("KeyframeIntervalSec"), 0,
  171. 10, 1);
  172. obs_property_int_set_suffix(p, " s");
  173. p = obs_properties_add_list(props, "preset2", obs_module_text("Preset"),
  174. OBS_COMBO_TYPE_LIST,
  175. OBS_COMBO_FORMAT_STRING);
  176. #define add_preset(val) \
  177. obs_property_list_add_string(p, obs_module_text("Preset." val), val)
  178. add_preset("p1");
  179. add_preset("p2");
  180. add_preset("p3");
  181. add_preset("p4");
  182. add_preset("p5");
  183. add_preset("p6");
  184. add_preset("p7");
  185. #undef add_preset
  186. p = obs_properties_add_list(props, "tune", obs_module_text("Tuning"),
  187. OBS_COMBO_TYPE_LIST,
  188. OBS_COMBO_FORMAT_STRING);
  189. #define add_tune(val) \
  190. obs_property_list_add_string(p, obs_module_text("Tuning." val), val)
  191. add_tune("hq");
  192. add_tune("ll");
  193. add_tune("ull");
  194. #undef add_tune
  195. p = obs_properties_add_list(props, "multipass",
  196. obs_module_text("Multipass"),
  197. OBS_COMBO_TYPE_LIST,
  198. OBS_COMBO_FORMAT_STRING);
  199. #define add_multipass(val) \
  200. obs_property_list_add_string(p, obs_module_text("Multipass." val), val)
  201. add_multipass("disabled");
  202. add_multipass("qres");
  203. add_multipass("fullres");
  204. #undef add_multipass
  205. p = obs_properties_add_list(props, "profile",
  206. obs_module_text("Profile"),
  207. OBS_COMBO_TYPE_LIST,
  208. OBS_COMBO_FORMAT_STRING);
  209. #define add_profile(val) obs_property_list_add_string(p, val, val)
  210. if (codec == CODEC_HEVC) {
  211. add_profile("main10");
  212. add_profile("main");
  213. } else if (codec == CODEC_AV1) {
  214. add_profile("main");
  215. } else {
  216. add_profile("high");
  217. add_profile("main");
  218. add_profile("baseline");
  219. }
  220. #undef add_profile
  221. p = obs_properties_add_bool(props, "lookahead",
  222. obs_module_text("LookAhead"));
  223. obs_property_set_long_description(p,
  224. obs_module_text("LookAhead.ToolTip"));
  225. p = obs_properties_add_bool(props, "repeat_headers", "repeat_headers");
  226. obs_property_set_visible(p, false);
  227. p = obs_properties_add_bool(props, "psycho_aq",
  228. obs_module_text("PsychoVisualTuning"));
  229. obs_property_set_long_description(
  230. p, obs_module_text("PsychoVisualTuning.ToolTip"));
  231. obs_properties_add_int(props, "gpu", obs_module_text("GPU"), 0, 8, 1);
  232. obs_properties_add_int(props, "bf", obs_module_text("BFrames"), 0, 4,
  233. 1);
  234. return props;
  235. }
  236. static obs_properties_t *h264_nvenc_properties(void *unused)
  237. {
  238. UNUSED_PARAMETER(unused);
  239. return nvenc_properties_internal(CODEC_H264);
  240. }
  241. #ifdef ENABLE_HEVC
  242. static obs_properties_t *hevc_nvenc_properties(void *unused)
  243. {
  244. UNUSED_PARAMETER(unused);
  245. return nvenc_properties_internal(CODEC_HEVC);
  246. }
  247. #endif
  248. static obs_properties_t *av1_nvenc_properties(void *unused)
  249. {
  250. UNUSED_PARAMETER(unused);
  251. return nvenc_properties_internal(CODEC_AV1);
  252. }
  253. /* ------------------------------------------------------------------------- */
  254. /* Stubs for required - but unused - functions. */
  255. static void fake_nvenc_destroy(void *p)
  256. {
  257. UNUSED_PARAMETER(p);
  258. }
  259. static bool fake_encode(void *data, struct encoder_frame *frame,
  260. struct encoder_packet *packet, bool *received_packet)
  261. {
  262. UNUSED_PARAMETER(data);
  263. UNUSED_PARAMETER(frame);
  264. UNUSED_PARAMETER(packet);
  265. UNUSED_PARAMETER(received_packet);
  266. return true;
  267. }
  268. static bool fake_encode_tex2(void *data, struct encoder_texture *texture,
  269. int64_t pts, uint64_t lock_key, uint64_t *next_key,
  270. struct encoder_packet *packet,
  271. bool *received_packet)
  272. {
  273. UNUSED_PARAMETER(data);
  274. UNUSED_PARAMETER(texture);
  275. UNUSED_PARAMETER(pts);
  276. UNUSED_PARAMETER(lock_key);
  277. UNUSED_PARAMETER(next_key);
  278. UNUSED_PARAMETER(packet);
  279. UNUSED_PARAMETER(received_packet);
  280. return true;
  281. }
  282. struct obs_encoder_info compat_h264_nvenc_info = {
  283. .id = "jim_nvenc",
  284. .codec = "h264",
  285. .type = OBS_ENCODER_VIDEO,
  286. .caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE |
  287. OBS_ENCODER_CAP_ROI | OBS_ENCODER_CAP_DEPRECATED,
  288. .get_name = h264_nvenc_get_name,
  289. .create = h264_nvenc_create,
  290. .destroy = fake_nvenc_destroy,
  291. .encode_texture2 = fake_encode_tex2,
  292. .get_defaults = h264_nvenc_defaults,
  293. .get_properties = h264_nvenc_properties,
  294. };
  295. #ifdef ENABLE_HEVC
  296. struct obs_encoder_info compat_hevc_nvenc_info = {
  297. .id = "jim_hevc_nvenc",
  298. .codec = "hevc",
  299. .type = OBS_ENCODER_VIDEO,
  300. .caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE |
  301. OBS_ENCODER_CAP_ROI | OBS_ENCODER_CAP_DEPRECATED,
  302. .get_name = hevc_nvenc_get_name,
  303. .create = hevc_nvenc_create,
  304. .destroy = fake_nvenc_destroy,
  305. .encode_texture2 = fake_encode_tex2,
  306. .get_defaults = hevc_nvenc_defaults,
  307. .get_properties = hevc_nvenc_properties,
  308. };
  309. #endif
  310. struct obs_encoder_info compat_av1_nvenc_info = {
  311. .id = "jim_av1_nvenc",
  312. .codec = "av1",
  313. .type = OBS_ENCODER_VIDEO,
  314. .caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE |
  315. OBS_ENCODER_CAP_ROI | OBS_ENCODER_CAP_DEPRECATED,
  316. .get_name = av1_nvenc_get_name,
  317. .create = av1_nvenc_create,
  318. .destroy = fake_nvenc_destroy,
  319. .encode_texture2 = fake_encode_tex2,
  320. .get_defaults = av1_nvenc_defaults,
  321. .get_properties = av1_nvenc_properties,
  322. };
  323. struct obs_encoder_info compat_h264_nvenc_soft_info = {
  324. .id = "obs_nvenc_h264_cuda",
  325. .codec = "h264",
  326. .type = OBS_ENCODER_VIDEO,
  327. .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_ROI |
  328. OBS_ENCODER_CAP_DEPRECATED,
  329. .get_name = h264_nvenc_get_name,
  330. .create = h264_nvenc_soft_create,
  331. .destroy = fake_nvenc_destroy,
  332. .encode = fake_encode,
  333. .get_defaults = h264_nvenc_defaults,
  334. .get_properties = h264_nvenc_properties,
  335. };
  336. #ifdef ENABLE_HEVC
  337. struct obs_encoder_info compat_hevc_nvenc_soft_info = {
  338. .id = "obs_nvenc_hevc_cuda",
  339. .codec = "hevc",
  340. .type = OBS_ENCODER_VIDEO,
  341. .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_ROI |
  342. OBS_ENCODER_CAP_DEPRECATED,
  343. .get_name = hevc_nvenc_get_name,
  344. .create = hevc_nvenc_soft_create,
  345. .destroy = fake_nvenc_destroy,
  346. .encode = fake_encode,
  347. .get_defaults = hevc_nvenc_defaults,
  348. .get_properties = hevc_nvenc_properties,
  349. };
  350. #endif
  351. struct obs_encoder_info compat_av1_nvenc_soft_info = {
  352. .id = "obs_nvenc_av1_cuda",
  353. .codec = "av1",
  354. .type = OBS_ENCODER_VIDEO,
  355. .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_ROI |
  356. OBS_ENCODER_CAP_DEPRECATED,
  357. .get_name = av1_nvenc_get_name,
  358. .create = av1_nvenc_soft_create,
  359. .destroy = fake_nvenc_destroy,
  360. .encode = fake_encode,
  361. .get_defaults = av1_nvenc_defaults,
  362. .get_properties = av1_nvenc_properties,
  363. };
  364. void register_compat_encoders(void)
  365. {
  366. obs_register_encoder(&compat_h264_nvenc_info);
  367. obs_register_encoder(&compat_h264_nvenc_soft_info);
  368. #ifdef ENABLE_HEVC
  369. obs_register_encoder(&compat_hevc_nvenc_info);
  370. obs_register_encoder(&compat_hevc_nvenc_soft_info);
  371. #endif
  372. if (is_codec_supported(CODEC_AV1)) {
  373. obs_register_encoder(&compat_av1_nvenc_info);
  374. obs_register_encoder(&compat_av1_nvenc_soft_info);
  375. }
  376. #ifdef REGISTER_FFMPEG_IDS
  377. compat_h264_nvenc_soft_info.id = "ffmpeg_nvenc";
  378. obs_register_encoder(&compat_h264_nvenc_soft_info);
  379. #ifdef ENABLE_HEVC
  380. compat_hevc_nvenc_soft_info.id = "ffmpeg_hevc_nvenc";
  381. obs_register_encoder(&compat_hevc_nvenc_soft_info);
  382. #endif
  383. #endif
  384. }