jim-nvenc.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  1. #include "jim-nvenc.h"
  2. #include <util/circlebuf.h>
  3. #include <util/darray.h>
  4. #include <util/dstr.h>
  5. #include <obs-avc.h>
  6. #define INITGUID
  7. #include <dxgi.h>
  8. #include <d3d11.h>
  9. #include <d3d11_1.h>
  10. /* ========================================================================= */
  11. #define EXTRA_BUFFERS 5
  12. #define do_log(level, format, ...) \
  13. blog(level, "[jim-nvenc: '%s'] " format, \
  14. obs_encoder_get_name(enc->encoder), ##__VA_ARGS__)
  15. #define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
  16. #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
  17. #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
  18. #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
  19. #define error_hr(msg) error("%s: %s: 0x%08lX", __FUNCTION__, msg, (uint32_t)hr);
  20. struct nv_bitstream;
  21. struct nv_texture;
  22. struct handle_tex {
  23. uint32_t handle;
  24. ID3D11Texture2D *tex;
  25. IDXGIKeyedMutex *km;
  26. };
  27. /* ------------------------------------------------------------------------- */
  28. /* Main Implementation Structure */
  29. struct nvenc_data {
  30. obs_encoder_t *encoder;
  31. void *session;
  32. NV_ENC_INITIALIZE_PARAMS params;
  33. NV_ENC_CONFIG config;
  34. size_t buf_count;
  35. size_t output_delay;
  36. size_t buffers_queued;
  37. size_t next_bitstream;
  38. size_t cur_bitstream;
  39. bool encode_started;
  40. bool first_packet;
  41. bool can_change_bitrate;
  42. bool bframes;
  43. DARRAY(struct nv_bitstream) bitstreams;
  44. DARRAY(struct nv_texture) textures;
  45. DARRAY(struct handle_tex) input_textures;
  46. struct circlebuf dts_list;
  47. DARRAY(uint8_t) packet_data;
  48. int64_t packet_pts;
  49. bool packet_keyframe;
  50. ID3D11Device *device;
  51. ID3D11DeviceContext *context;
  52. uint32_t cx;
  53. uint32_t cy;
  54. uint8_t *header;
  55. size_t header_size;
  56. uint8_t *sei;
  57. size_t sei_size;
  58. };
  59. /* ------------------------------------------------------------------------- */
  60. /* Bitstream Buffer */
  61. struct nv_bitstream {
  62. void *ptr;
  63. HANDLE event;
  64. };
  65. #define NV_FAILED(x) nv_failed(enc->encoder, x, __FUNCTION__, #x)
  66. static bool nv_bitstream_init(struct nvenc_data *enc, struct nv_bitstream *bs)
  67. {
  68. NV_ENC_CREATE_BITSTREAM_BUFFER buf = {
  69. NV_ENC_CREATE_BITSTREAM_BUFFER_VER};
  70. NV_ENC_EVENT_PARAMS params = {NV_ENC_EVENT_PARAMS_VER};
  71. HANDLE event = NULL;
  72. if (NV_FAILED(nv.nvEncCreateBitstreamBuffer(enc->session, &buf))) {
  73. return false;
  74. }
  75. event = CreateEvent(NULL, true, true, NULL);
  76. if (!event) {
  77. error("%s: %s", __FUNCTION__, "Failed to create event");
  78. goto fail;
  79. }
  80. params.completionEvent = event;
  81. if (NV_FAILED(nv.nvEncRegisterAsyncEvent(enc->session, &params))) {
  82. goto fail;
  83. }
  84. bs->ptr = buf.bitstreamBuffer;
  85. bs->event = event;
  86. return true;
  87. fail:
  88. if (event) {
  89. CloseHandle(event);
  90. }
  91. if (buf.bitstreamBuffer) {
  92. nv.nvEncDestroyBitstreamBuffer(enc->session,
  93. buf.bitstreamBuffer);
  94. }
  95. return false;
  96. }
  97. static void nv_bitstream_free(struct nvenc_data *enc, struct nv_bitstream *bs)
  98. {
  99. if (bs->ptr) {
  100. nv.nvEncDestroyBitstreamBuffer(enc->session, bs->ptr);
  101. NV_ENC_EVENT_PARAMS params = {NV_ENC_EVENT_PARAMS_VER};
  102. params.completionEvent = bs->event;
  103. nv.nvEncUnregisterAsyncEvent(enc->session, &params);
  104. CloseHandle(bs->event);
  105. }
  106. }
  107. /* ------------------------------------------------------------------------- */
  108. /* Texture Resource */
  109. struct nv_texture {
  110. void *res;
  111. ID3D11Texture2D *tex;
  112. void *mapped_res;
  113. };
  114. static bool nv_texture_init(struct nvenc_data *enc, struct nv_texture *nvtex)
  115. {
  116. ID3D11Device *device = enc->device;
  117. ID3D11Texture2D *tex;
  118. HRESULT hr;
  119. D3D11_TEXTURE2D_DESC desc = {0};
  120. desc.Width = enc->cx;
  121. desc.Height = enc->cy;
  122. desc.MipLevels = 1;
  123. desc.ArraySize = 1;
  124. desc.Format = DXGI_FORMAT_NV12;
  125. desc.SampleDesc.Count = 1;
  126. desc.BindFlags = D3D11_BIND_RENDER_TARGET;
  127. hr = device->lpVtbl->CreateTexture2D(device, &desc, NULL, &tex);
  128. if (FAILED(hr)) {
  129. error_hr("Failed to create texture");
  130. return false;
  131. }
  132. tex->lpVtbl->SetEvictionPriority(tex, DXGI_RESOURCE_PRIORITY_MAXIMUM);
  133. NV_ENC_REGISTER_RESOURCE res = {NV_ENC_REGISTER_RESOURCE_VER};
  134. res.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
  135. res.resourceToRegister = tex;
  136. res.width = enc->cx;
  137. res.height = enc->cy;
  138. res.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
  139. if (NV_FAILED(nv.nvEncRegisterResource(enc->session, &res))) {
  140. tex->lpVtbl->Release(tex);
  141. return false;
  142. }
  143. nvtex->res = res.registeredResource;
  144. nvtex->tex = tex;
  145. return true;
  146. }
  147. static void nv_texture_free(struct nvenc_data *enc, struct nv_texture *nvtex)
  148. {
  149. if (nvtex->res) {
  150. if (nvtex->mapped_res) {
  151. nv.nvEncUnmapInputResource(enc->session,
  152. nvtex->mapped_res);
  153. }
  154. nv.nvEncUnregisterResource(enc->session, nvtex->res);
  155. nvtex->tex->lpVtbl->Release(nvtex->tex);
  156. }
  157. }
  158. /* ------------------------------------------------------------------------- */
  159. /* Implementation */
  160. static const char *nvenc_get_name(void *type_data)
  161. {
  162. UNUSED_PARAMETER(type_data);
  163. return "NVIDIA NVENC H.264 (new)";
  164. }
  165. static inline int nv_get_cap(struct nvenc_data *enc, NV_ENC_CAPS cap)
  166. {
  167. if (!enc->session)
  168. return 0;
  169. NV_ENC_CAPS_PARAM param = {NV_ENC_CAPS_PARAM_VER};
  170. int v;
  171. param.capsToQuery = cap;
  172. nv.nvEncGetEncodeCaps(enc->session, NV_ENC_CODEC_H264_GUID, &param, &v);
  173. return v;
  174. }
  175. static bool nvenc_update(void *data, obs_data_t *settings)
  176. {
  177. struct nvenc_data *enc = data;
  178. /* Only support reconfiguration of CBR bitrate */
  179. if (enc->can_change_bitrate) {
  180. int bitrate = (int)obs_data_get_int(settings, "bitrate");
  181. enc->config.rcParams.averageBitRate = bitrate * 1000;
  182. enc->config.rcParams.maxBitRate = bitrate * 1000;
  183. NV_ENC_RECONFIGURE_PARAMS params = {0};
  184. params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
  185. params.reInitEncodeParams = enc->params;
  186. params.resetEncoder = 1;
  187. params.forceIDR = 1;
  188. if (NV_FAILED(nv.nvEncReconfigureEncoder(enc->session,
  189. &params))) {
  190. return false;
  191. }
  192. }
  193. return true;
  194. }
  195. static HANDLE get_lib(struct nvenc_data *enc, const char *lib)
  196. {
  197. HMODULE mod = GetModuleHandleA(lib);
  198. if (mod)
  199. return mod;
  200. mod = LoadLibraryA(lib);
  201. if (!mod)
  202. error("Failed to load %s", lib);
  203. return mod;
  204. }
  205. typedef HRESULT(WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
  206. static bool init_d3d11(struct nvenc_data *enc, obs_data_t *settings)
  207. {
  208. HMODULE dxgi = get_lib(enc, "DXGI.dll");
  209. HMODULE d3d11 = get_lib(enc, "D3D11.dll");
  210. CREATEDXGIFACTORY1PROC create_dxgi;
  211. PFN_D3D11_CREATE_DEVICE create_device;
  212. IDXGIFactory1 *factory;
  213. IDXGIAdapter *adapter;
  214. ID3D11Device *device;
  215. ID3D11DeviceContext *context;
  216. HRESULT hr;
  217. if (!dxgi || !d3d11) {
  218. return false;
  219. }
  220. create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress(
  221. dxgi, "CreateDXGIFactory1");
  222. create_device = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(
  223. d3d11, "D3D11CreateDevice");
  224. if (!create_dxgi || !create_device) {
  225. error("Failed to load D3D11/DXGI procedures");
  226. return false;
  227. }
  228. hr = create_dxgi(&IID_IDXGIFactory1, &factory);
  229. if (FAILED(hr)) {
  230. error_hr("CreateDXGIFactory1 failed");
  231. return false;
  232. }
  233. hr = factory->lpVtbl->EnumAdapters(factory, 0, &adapter);
  234. factory->lpVtbl->Release(factory);
  235. if (FAILED(hr)) {
  236. error_hr("EnumAdapters failed");
  237. return false;
  238. }
  239. hr = create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0,
  240. D3D11_SDK_VERSION, &device, NULL, &context);
  241. adapter->lpVtbl->Release(adapter);
  242. if (FAILED(hr)) {
  243. error_hr("D3D11CreateDevice failed");
  244. return false;
  245. }
  246. enc->device = device;
  247. enc->context = context;
  248. return true;
  249. }
  250. static bool init_session(struct nvenc_data *enc)
  251. {
  252. NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = {
  253. NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER};
  254. params.device = enc->device;
  255. params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
  256. params.apiVersion = NVENCAPI_VERSION;
  257. if (NV_FAILED(nv.nvEncOpenEncodeSessionEx(&params, &enc->session))) {
  258. return false;
  259. }
  260. return true;
  261. }
  262. static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
  263. {
  264. const char *rc = obs_data_get_string(settings, "rate_control");
  265. int bitrate = (int)obs_data_get_int(settings, "bitrate");
  266. int max_bitrate = (int)obs_data_get_int(settings, "max_bitrate");
  267. int cqp = (int)obs_data_get_int(settings, "cqp");
  268. int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
  269. const char *preset = obs_data_get_string(settings, "preset");
  270. const char *profile = obs_data_get_string(settings, "profile");
  271. bool psycho_aq = obs_data_get_bool(settings, "psycho_aq");
  272. bool lookahead = obs_data_get_bool(settings, "lookahead");
  273. int bf = (int)obs_data_get_int(settings, "bf");
  274. bool vbr = astrcmpi(rc, "VBR") == 0;
  275. NVENCSTATUS err;
  276. video_t *video = obs_encoder_video(enc->encoder);
  277. const struct video_output_info *voi = video_output_get_info(video);
  278. enc->cx = voi->width;
  279. enc->cy = voi->height;
  280. /* -------------------------- */
  281. /* get preset */
  282. GUID nv_preset = NV_ENC_PRESET_DEFAULT_GUID;
  283. bool twopass = false;
  284. bool hp = false;
  285. bool ll = false;
  286. if (astrcmpi(preset, "hq") == 0) {
  287. nv_preset = NV_ENC_PRESET_HQ_GUID;
  288. } else if (astrcmpi(preset, "mq") == 0) {
  289. nv_preset = NV_ENC_PRESET_HQ_GUID;
  290. twopass = true;
  291. } else if (astrcmpi(preset, "hp") == 0) {
  292. nv_preset = NV_ENC_PRESET_HP_GUID;
  293. hp = true;
  294. } else if (astrcmpi(preset, "ll") == 0) {
  295. nv_preset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
  296. ll = true;
  297. } else if (astrcmpi(preset, "llhq") == 0) {
  298. nv_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
  299. ll = true;
  300. } else if (astrcmpi(preset, "llhp") == 0) {
  301. nv_preset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
  302. hp = true;
  303. ll = true;
  304. }
  305. if (astrcmpi(rc, "lossless") == 0) {
  306. nv_preset = hp ? NV_ENC_PRESET_LOSSLESS_HP_GUID
  307. : NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
  308. }
  309. /* -------------------------- */
  310. /* get preset default config */
  311. NV_ENC_PRESET_CONFIG preset_config = {NV_ENC_PRESET_CONFIG_VER,
  312. {NV_ENC_CONFIG_VER}};
  313. err = nv.nvEncGetEncodePresetConfig(enc->session,
  314. NV_ENC_CODEC_H264_GUID, nv_preset,
  315. &preset_config);
  316. if (nv_failed(enc->encoder, err, __FUNCTION__,
  317. "nvEncGetEncodePresetConfig")) {
  318. return false;
  319. }
  320. /* -------------------------- */
  321. /* main configuration */
  322. enc->config = preset_config.presetCfg;
  323. uint32_t gop_size =
  324. (keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
  325. NV_ENC_INITIALIZE_PARAMS *params = &enc->params;
  326. NV_ENC_CONFIG *config = &enc->config;
  327. NV_ENC_CONFIG_H264 *h264_config = &config->encodeCodecConfig.h264Config;
  328. NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui_params =
  329. &h264_config->h264VUIParameters;
  330. memset(params, 0, sizeof(*params));
  331. params->version = NV_ENC_INITIALIZE_PARAMS_VER;
  332. params->encodeGUID = NV_ENC_CODEC_H264_GUID;
  333. params->presetGUID = nv_preset;
  334. params->encodeWidth = voi->width;
  335. params->encodeHeight = voi->height;
  336. params->darWidth = voi->width;
  337. params->darHeight = voi->height;
  338. params->frameRateNum = voi->fps_num;
  339. params->frameRateDen = voi->fps_den;
  340. params->enableEncodeAsync = 1;
  341. params->enablePTD = 1;
  342. params->encodeConfig = &enc->config;
  343. params->maxEncodeWidth = voi->width;
  344. params->maxEncodeHeight = voi->height;
  345. config->gopLength = gop_size;
  346. config->frameIntervalP = 1 + bf;
  347. h264_config->idrPeriod = gop_size;
  348. bool repeat_headers = obs_data_get_bool(settings, "repeat_headers");
  349. if (repeat_headers) {
  350. h264_config->repeatSPSPPS = 1;
  351. h264_config->disableSPSPPS = 0;
  352. h264_config->outputAUD = 1;
  353. }
  354. vui_params->videoSignalTypePresentFlag = 1;
  355. vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
  356. vui_params->colourDescriptionPresentFlag = 1;
  357. switch (voi->colorspace) {
  358. case VIDEO_CS_601:
  359. vui_params->colourPrimaries = 6;
  360. vui_params->transferCharacteristics = 6;
  361. vui_params->colourMatrix = 6;
  362. break;
  363. case VIDEO_CS_DEFAULT:
  364. case VIDEO_CS_709:
  365. vui_params->colourPrimaries = 1;
  366. vui_params->transferCharacteristics = 1;
  367. vui_params->colourMatrix = 1;
  368. break;
  369. case VIDEO_CS_SRGB:
  370. vui_params->colourPrimaries = 1;
  371. vui_params->transferCharacteristics = 13;
  372. vui_params->colourMatrix = 1;
  373. break;
  374. }
  375. enc->bframes = bf > 0;
  376. /* lookahead */
  377. if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) {
  378. config->rcParams.lookaheadDepth = 8;
  379. config->rcParams.enableLookahead = 1;
  380. } else {
  381. lookahead = false;
  382. }
  383. /* psycho aq */
  384. if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) {
  385. config->rcParams.enableAQ = psycho_aq;
  386. config->rcParams.enableTemporalAQ = psycho_aq;
  387. }
  388. /* -------------------------- */
  389. /* rate control */
  390. enc->can_change_bitrate =
  391. nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) &&
  392. !lookahead;
  393. config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ
  394. : NV_ENC_PARAMS_RC_VBR;
  395. if (astrcmpi(rc, "cqp") == 0 || astrcmpi(rc, "lossless") == 0) {
  396. if (astrcmpi(rc, "lossless") == 0)
  397. cqp = 0;
  398. config->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
  399. config->rcParams.constQP.qpInterP = cqp;
  400. config->rcParams.constQP.qpInterB = cqp;
  401. config->rcParams.constQP.qpIntra = cqp;
  402. enc->can_change_bitrate = false;
  403. bitrate = 0;
  404. max_bitrate = 0;
  405. } else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
  406. h264_config->outputBufferingPeriodSEI = 1;
  407. config->rcParams.rateControlMode =
  408. twopass ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
  409. : NV_ENC_PARAMS_RC_CBR;
  410. }
  411. h264_config->outputPictureTimingSEI = 1;
  412. config->rcParams.averageBitRate = bitrate * 1000;
  413. config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
  414. /* -------------------------- */
  415. /* profile */
  416. if (astrcmpi(profile, "main") == 0) {
  417. config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
  418. } else if (astrcmpi(profile, "baseline") == 0) {
  419. config->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
  420. } else {
  421. config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
  422. }
  423. /* -------------------------- */
  424. /* initialize */
  425. if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, params))) {
  426. return false;
  427. }
  428. enc->buf_count = config->frameIntervalP +
  429. config->rcParams.lookaheadDepth + EXTRA_BUFFERS;
  430. enc->output_delay = enc->buf_count - 1;
  431. info("settings:\n"
  432. "\trate_control: %s\n"
  433. "\tbitrate: %d\n"
  434. "\tcqp: %d\n"
  435. "\tkeyint: %d\n"
  436. "\tpreset: %s\n"
  437. "\tprofile: %s\n"
  438. "\twidth: %d\n"
  439. "\theight: %d\n"
  440. "\t2-pass: %s\n"
  441. "\tb-frames: %d\n"
  442. "\tlookahead: %s\n"
  443. "\tpsycho_aq: %s\n",
  444. rc, bitrate, cqp, gop_size, preset, profile, enc->cx, enc->cy,
  445. twopass ? "true" : "false", bf, lookahead ? "true" : "false",
  446. psycho_aq ? "true" : "false");
  447. return true;
  448. }
  449. static bool init_bitstreams(struct nvenc_data *enc)
  450. {
  451. da_reserve(enc->bitstreams, enc->buf_count);
  452. for (size_t i = 0; i < enc->buf_count; i++) {
  453. struct nv_bitstream bitstream;
  454. if (!nv_bitstream_init(enc, &bitstream)) {
  455. return false;
  456. }
  457. da_push_back(enc->bitstreams, &bitstream);
  458. }
  459. return true;
  460. }
  461. static bool init_textures(struct nvenc_data *enc)
  462. {
  463. da_reserve(enc->bitstreams, enc->buf_count);
  464. for (size_t i = 0; i < enc->buf_count; i++) {
  465. struct nv_texture texture;
  466. if (!nv_texture_init(enc, &texture)) {
  467. return false;
  468. }
  469. da_push_back(enc->textures, &texture);
  470. }
  471. return true;
  472. }
  473. static void nvenc_destroy(void *data);
  474. static void *nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
  475. {
  476. NV_ENCODE_API_FUNCTION_LIST init = {NV_ENCODE_API_FUNCTION_LIST_VER};
  477. struct nvenc_data *enc = bzalloc(sizeof(*enc));
  478. enc->encoder = encoder;
  479. enc->first_packet = true;
  480. /* this encoder requires shared textures, this cannot be used on a
  481. * gpu other than the one OBS is currently running on. */
  482. int gpu = (int)obs_data_get_int(settings, "gpu");
  483. if (gpu != 0) {
  484. info("different GPU selected by user, falling back to ffmpeg");
  485. goto fail;
  486. }
  487. if (obs_encoder_scaling_enabled(encoder)) {
  488. info("scaling enabled, falling back to ffmpeg");
  489. goto fail;
  490. }
  491. if (!obs_nv12_tex_active()) {
  492. info("nv12 not active, falling back to ffmpeg");
  493. goto fail;
  494. }
  495. if (!init_nvenc(encoder)) {
  496. goto fail;
  497. }
  498. if (NV_FAILED(nv_create_instance(&init))) {
  499. goto fail;
  500. }
  501. if (!init_d3d11(enc, settings)) {
  502. goto fail;
  503. }
  504. if (!init_session(enc)) {
  505. goto fail;
  506. }
  507. if (!init_encoder(enc, settings)) {
  508. goto fail;
  509. }
  510. if (!init_bitstreams(enc)) {
  511. goto fail;
  512. }
  513. if (!init_textures(enc)) {
  514. goto fail;
  515. }
  516. return enc;
  517. fail:
  518. nvenc_destroy(enc);
  519. return obs_encoder_create_rerouted(encoder, "ffmpeg_nvenc");
  520. }
  521. static bool get_encoded_packet(struct nvenc_data *enc, bool finalize);
  522. static void nvenc_destroy(void *data)
  523. {
  524. struct nvenc_data *enc = data;
  525. if (enc->encode_started) {
  526. size_t next_bitstream = enc->next_bitstream;
  527. HANDLE next_event = enc->bitstreams.array[next_bitstream].event;
  528. NV_ENC_PIC_PARAMS params = {NV_ENC_PIC_PARAMS_VER};
  529. params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
  530. params.completionEvent = next_event;
  531. nv.nvEncEncodePicture(enc->session, &params);
  532. get_encoded_packet(enc, true);
  533. }
  534. for (size_t i = 0; i < enc->textures.num; i++) {
  535. nv_texture_free(enc, &enc->textures.array[i]);
  536. }
  537. for (size_t i = 0; i < enc->bitstreams.num; i++) {
  538. nv_bitstream_free(enc, &enc->bitstreams.array[i]);
  539. }
  540. if (enc->session) {
  541. nv.nvEncDestroyEncoder(enc->session);
  542. }
  543. for (size_t i = 0; i < enc->input_textures.num; i++) {
  544. ID3D11Texture2D *tex = enc->input_textures.array[i].tex;
  545. IDXGIKeyedMutex *km = enc->input_textures.array[i].km;
  546. tex->lpVtbl->Release(tex);
  547. km->lpVtbl->Release(km);
  548. }
  549. if (enc->context) {
  550. enc->context->lpVtbl->Release(enc->context);
  551. }
  552. if (enc->device) {
  553. enc->device->lpVtbl->Release(enc->device);
  554. }
  555. bfree(enc->header);
  556. bfree(enc->sei);
  557. circlebuf_free(&enc->dts_list);
  558. da_free(enc->textures);
  559. da_free(enc->bitstreams);
  560. da_free(enc->input_textures);
  561. da_free(enc->packet_data);
  562. bfree(enc);
  563. }
  564. static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc,
  565. uint32_t handle,
  566. IDXGIKeyedMutex **km_out)
  567. {
  568. ID3D11Device *device = enc->device;
  569. IDXGIKeyedMutex *km;
  570. ID3D11Texture2D *input_tex;
  571. HRESULT hr;
  572. for (size_t i = 0; i < enc->input_textures.num; i++) {
  573. struct handle_tex *ht = &enc->input_textures.array[i];
  574. if (ht->handle == handle) {
  575. *km_out = ht->km;
  576. return ht->tex;
  577. }
  578. }
  579. hr = device->lpVtbl->OpenSharedResource(device,
  580. (HANDLE)(uintptr_t)handle,
  581. &IID_ID3D11Texture2D,
  582. &input_tex);
  583. if (FAILED(hr)) {
  584. error_hr("OpenSharedResource failed");
  585. return NULL;
  586. }
  587. hr = input_tex->lpVtbl->QueryInterface(input_tex, &IID_IDXGIKeyedMutex,
  588. &km);
  589. if (FAILED(hr)) {
  590. error_hr("QueryInterface(IDXGIKeyedMutex) failed");
  591. input_tex->lpVtbl->Release(input_tex);
  592. return NULL;
  593. }
  594. input_tex->lpVtbl->SetEvictionPriority(input_tex,
  595. DXGI_RESOURCE_PRIORITY_MAXIMUM);
  596. *km_out = km;
  597. struct handle_tex new_ht = {handle, input_tex, km};
  598. da_push_back(enc->input_textures, &new_ht);
  599. return input_tex;
  600. }
  601. static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
  602. {
  603. void *s = enc->session;
  604. da_resize(enc->packet_data, 0);
  605. if (!enc->buffers_queued)
  606. return true;
  607. if (!finalize && enc->buffers_queued < enc->output_delay)
  608. return true;
  609. size_t count = finalize ? enc->buffers_queued : 1;
  610. for (size_t i = 0; i < count; i++) {
  611. size_t cur_bs_idx = enc->cur_bitstream;
  612. struct nv_bitstream *bs = &enc->bitstreams.array[cur_bs_idx];
  613. struct nv_texture *nvtex = &enc->textures.array[cur_bs_idx];
  614. /* ---------------- */
  615. NV_ENC_LOCK_BITSTREAM lock = {NV_ENC_LOCK_BITSTREAM_VER};
  616. lock.outputBitstream = bs->ptr;
  617. lock.doNotWait = false;
  618. if (NV_FAILED(nv.nvEncLockBitstream(s, &lock))) {
  619. return false;
  620. }
  621. if (enc->first_packet) {
  622. uint8_t *new_packet;
  623. size_t size;
  624. enc->first_packet = false;
  625. obs_extract_avc_headers(lock.bitstreamBufferPtr,
  626. lock.bitstreamSizeInBytes,
  627. &new_packet, &size,
  628. &enc->header, &enc->header_size,
  629. &enc->sei, &enc->sei_size);
  630. da_copy_array(enc->packet_data, new_packet, size);
  631. bfree(new_packet);
  632. } else {
  633. da_copy_array(enc->packet_data, lock.bitstreamBufferPtr,
  634. lock.bitstreamSizeInBytes);
  635. }
  636. enc->packet_pts = (int64_t)lock.outputTimeStamp;
  637. enc->packet_keyframe = lock.pictureType == NV_ENC_PIC_TYPE_IDR;
  638. if (NV_FAILED(nv.nvEncUnlockBitstream(s, bs->ptr))) {
  639. return false;
  640. }
  641. /* ---------------- */
  642. if (nvtex->mapped_res) {
  643. NVENCSTATUS err;
  644. err = nv.nvEncUnmapInputResource(s, nvtex->mapped_res);
  645. if (nv_failed(enc->encoder, err, __FUNCTION__,
  646. "unmap")) {
  647. return false;
  648. }
  649. nvtex->mapped_res = NULL;
  650. }
  651. /* ---------------- */
  652. if (++enc->cur_bitstream == enc->buf_count)
  653. enc->cur_bitstream = 0;
  654. enc->buffers_queued--;
  655. }
  656. return true;
  657. }
  658. static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
  659. uint64_t lock_key, uint64_t *next_key,
  660. struct encoder_packet *packet,
  661. bool *received_packet)
  662. {
  663. struct nvenc_data *enc = data;
  664. ID3D11Device *device = enc->device;
  665. ID3D11DeviceContext *context = enc->context;
  666. ID3D11Texture2D *input_tex;
  667. ID3D11Texture2D *output_tex;
  668. IDXGIKeyedMutex *km;
  669. struct nv_texture *nvtex;
  670. struct nv_bitstream *bs;
  671. NVENCSTATUS err;
  672. if (handle == GS_INVALID_HANDLE) {
  673. error("Encode failed: bad texture handle");
  674. *next_key = lock_key;
  675. return false;
  676. }
  677. bs = &enc->bitstreams.array[enc->next_bitstream];
  678. nvtex = &enc->textures.array[enc->next_bitstream];
  679. input_tex = get_tex_from_handle(enc, handle, &km);
  680. output_tex = nvtex->tex;
  681. if (!input_tex) {
  682. *next_key = lock_key;
  683. return false;
  684. }
  685. circlebuf_push_back(&enc->dts_list, &pts, sizeof(pts));
  686. /* ------------------------------------ */
  687. /* wait for output bitstream/tex */
  688. WaitForSingleObject(bs->event, INFINITE);
  689. /* ------------------------------------ */
  690. /* copy to output tex */
  691. km->lpVtbl->AcquireSync(km, lock_key, INFINITE);
  692. context->lpVtbl->CopyResource(context, (ID3D11Resource *)output_tex,
  693. (ID3D11Resource *)input_tex);
  694. km->lpVtbl->ReleaseSync(km, *next_key);
  695. /* ------------------------------------ */
  696. /* map output tex so nvenc can use it */
  697. NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
  698. map.registeredResource = nvtex->res;
  699. if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map))) {
  700. return false;
  701. }
  702. nvtex->mapped_res = map.mappedResource;
  703. /* ------------------------------------ */
  704. /* do actual encode call */
  705. NV_ENC_PIC_PARAMS params = {0};
  706. params.version = NV_ENC_PIC_PARAMS_VER;
  707. params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
  708. params.inputBuffer = nvtex->mapped_res;
  709. params.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
  710. params.inputTimeStamp = (uint64_t)pts;
  711. params.inputWidth = enc->cx;
  712. params.inputHeight = enc->cy;
  713. params.outputBitstream = bs->ptr;
  714. params.completionEvent = bs->event;
  715. err = nv.nvEncEncodePicture(enc->session, &params);
  716. if (err != NV_ENC_SUCCESS && err != NV_ENC_ERR_NEED_MORE_INPUT) {
  717. nv_failed(enc->encoder, err, __FUNCTION__,
  718. "nvEncEncodePicture");
  719. return false;
  720. }
  721. enc->encode_started = true;
  722. enc->buffers_queued++;
  723. if (++enc->next_bitstream == enc->buf_count) {
  724. enc->next_bitstream = 0;
  725. }
  726. /* ------------------------------------ */
  727. /* check for encoded packet and parse */
  728. if (!get_encoded_packet(enc, false)) {
  729. return false;
  730. }
  731. /* ------------------------------------ */
  732. /* output encoded packet */
  733. if (enc->packet_data.num) {
  734. int64_t dts;
  735. circlebuf_pop_front(&enc->dts_list, &dts, sizeof(dts));
  736. /* subtract bframe delay from dts */
  737. if (enc->bframes)
  738. dts -= packet->timebase_num;
  739. *received_packet = true;
  740. packet->data = enc->packet_data.array;
  741. packet->size = enc->packet_data.num;
  742. packet->type = OBS_ENCODER_VIDEO;
  743. packet->pts = enc->packet_pts;
  744. packet->dts = dts;
  745. packet->keyframe = enc->packet_keyframe;
  746. } else {
  747. *received_packet = false;
  748. }
  749. return true;
  750. }
  751. extern void nvenc_defaults(obs_data_t *settings);
  752. extern obs_properties_t *nvenc_properties(void *unused);
  753. static bool nvenc_extra_data(void *data, uint8_t **header, size_t *size)
  754. {
  755. struct nvenc_data *enc = data;
  756. if (!enc->header) {
  757. return false;
  758. }
  759. *header = enc->header;
  760. *size = enc->header_size;
  761. return true;
  762. }
  763. static bool nvenc_sei_data(void *data, uint8_t **sei, size_t *size)
  764. {
  765. struct nvenc_data *enc = data;
  766. if (!enc->sei) {
  767. return false;
  768. }
  769. *sei = enc->sei;
  770. *size = enc->sei_size;
  771. return true;
  772. }
  773. struct obs_encoder_info nvenc_info = {
  774. .id = "jim_nvenc",
  775. .codec = "h264",
  776. .type = OBS_ENCODER_VIDEO,
  777. .caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE,
  778. .get_name = nvenc_get_name,
  779. .create = nvenc_create,
  780. .destroy = nvenc_destroy,
  781. .update = nvenc_update,
  782. .encode_texture = nvenc_encode_tex,
  783. .get_defaults = nvenc_defaults,
  784. .get_properties = nvenc_properties,
  785. .get_extra_data = nvenc_extra_data,
  786. .get_sei_data = nvenc_sei_data,
  787. };