nvenc-compat.c 13 KB

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