nvenc-compat.c 12 KB

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