jim-nvenc.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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. vui_params->videoSignalTypePresentFlag = 1;
  349. vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
  350. vui_params->colourDescriptionPresentFlag = 1;
  351. vui_params->colourMatrix = (voi->colorspace == VIDEO_CS_709) ? 1 : 5;
  352. vui_params->colourPrimaries = 1;
  353. vui_params->transferCharacteristics = 1;
  354. enc->bframes = bf > 0;
  355. /* lookahead */
  356. if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) {
  357. config->rcParams.lookaheadDepth = 8;
  358. config->rcParams.enableLookahead = 1;
  359. } else {
  360. lookahead = false;
  361. }
  362. /* psycho aq */
  363. if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) {
  364. config->rcParams.enableAQ = psycho_aq;
  365. config->rcParams.enableTemporalAQ = psycho_aq;
  366. }
  367. /* -------------------------- */
  368. /* rate control */
  369. enc->can_change_bitrate =
  370. nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) &&
  371. !lookahead;
  372. config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ
  373. : NV_ENC_PARAMS_RC_VBR;
  374. if (astrcmpi(rc, "cqp") == 0 || astrcmpi(rc, "lossless") == 0) {
  375. if (astrcmpi(rc, "lossless") == 0)
  376. cqp = 0;
  377. config->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
  378. config->rcParams.constQP.qpInterP = cqp;
  379. config->rcParams.constQP.qpInterB = cqp;
  380. config->rcParams.constQP.qpIntra = cqp;
  381. enc->can_change_bitrate = false;
  382. bitrate = 0;
  383. max_bitrate = 0;
  384. } else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
  385. h264_config->outputBufferingPeriodSEI = 1;
  386. config->rcParams.rateControlMode =
  387. twopass ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
  388. : NV_ENC_PARAMS_RC_CBR;
  389. }
  390. h264_config->outputPictureTimingSEI = 1;
  391. config->rcParams.averageBitRate = bitrate * 1000;
  392. config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
  393. /* -------------------------- */
  394. /* profile */
  395. if (astrcmpi(profile, "main") == 0) {
  396. config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
  397. } else if (astrcmpi(profile, "baseline") == 0) {
  398. config->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
  399. } else {
  400. config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
  401. }
  402. /* -------------------------- */
  403. /* initialize */
  404. if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, params))) {
  405. return false;
  406. }
  407. enc->buf_count = config->frameIntervalP +
  408. config->rcParams.lookaheadDepth + EXTRA_BUFFERS;
  409. enc->output_delay = enc->buf_count - 1;
  410. info("settings:\n"
  411. "\trate_control: %s\n"
  412. "\tbitrate: %d\n"
  413. "\tcqp: %d\n"
  414. "\tkeyint: %d\n"
  415. "\tpreset: %s\n"
  416. "\tprofile: %s\n"
  417. "\twidth: %d\n"
  418. "\theight: %d\n"
  419. "\t2-pass: %s\n"
  420. "\tb-frames: %d\n"
  421. "\tlookahead: %s\n"
  422. "\tpsycho_aq: %s\n",
  423. rc, bitrate, cqp, gop_size, preset, profile, enc->cx, enc->cy,
  424. twopass ? "true" : "false", bf, lookahead ? "true" : "false",
  425. psycho_aq ? "true" : "false");
  426. return true;
  427. }
  428. static bool init_bitstreams(struct nvenc_data *enc)
  429. {
  430. da_reserve(enc->bitstreams, enc->buf_count);
  431. for (size_t i = 0; i < enc->buf_count; i++) {
  432. struct nv_bitstream bitstream;
  433. if (!nv_bitstream_init(enc, &bitstream)) {
  434. return false;
  435. }
  436. da_push_back(enc->bitstreams, &bitstream);
  437. }
  438. return true;
  439. }
  440. static bool init_textures(struct nvenc_data *enc)
  441. {
  442. da_reserve(enc->bitstreams, enc->buf_count);
  443. for (size_t i = 0; i < enc->buf_count; i++) {
  444. struct nv_texture texture;
  445. if (!nv_texture_init(enc, &texture)) {
  446. return false;
  447. }
  448. da_push_back(enc->textures, &texture);
  449. }
  450. return true;
  451. }
  452. static void nvenc_destroy(void *data);
  453. static void *nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
  454. {
  455. NV_ENCODE_API_FUNCTION_LIST init = {NV_ENCODE_API_FUNCTION_LIST_VER};
  456. struct nvenc_data *enc = bzalloc(sizeof(*enc));
  457. enc->encoder = encoder;
  458. enc->first_packet = true;
  459. /* this encoder requires shared textures, this cannot be used on a
  460. * gpu other than the one OBS is currently running on. */
  461. int gpu = (int)obs_data_get_int(settings, "gpu");
  462. if (gpu != 0) {
  463. info("different GPU selected by user, falling back to ffmpeg");
  464. goto fail;
  465. }
  466. if (obs_encoder_scaling_enabled(encoder)) {
  467. info("scaling enabled, falling back to ffmpeg");
  468. goto fail;
  469. }
  470. if (!obs_nv12_tex_active()) {
  471. info("nv12 not active, falling back to ffmpeg");
  472. goto fail;
  473. }
  474. if (!init_nvenc(encoder)) {
  475. goto fail;
  476. }
  477. if (NV_FAILED(nv_create_instance(&init))) {
  478. goto fail;
  479. }
  480. if (!init_d3d11(enc, settings)) {
  481. goto fail;
  482. }
  483. if (!init_session(enc)) {
  484. goto fail;
  485. }
  486. if (!init_encoder(enc, settings)) {
  487. goto fail;
  488. }
  489. if (!init_bitstreams(enc)) {
  490. goto fail;
  491. }
  492. if (!init_textures(enc)) {
  493. goto fail;
  494. }
  495. return enc;
  496. fail:
  497. nvenc_destroy(enc);
  498. return obs_encoder_create_rerouted(encoder, "ffmpeg_nvenc");
  499. }
  500. static bool get_encoded_packet(struct nvenc_data *enc, bool finalize);
  501. static void nvenc_destroy(void *data)
  502. {
  503. struct nvenc_data *enc = data;
  504. if (enc->encode_started) {
  505. size_t next_bitstream = enc->next_bitstream;
  506. HANDLE next_event = enc->bitstreams.array[next_bitstream].event;
  507. NV_ENC_PIC_PARAMS params = {NV_ENC_PIC_PARAMS_VER};
  508. params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
  509. params.completionEvent = next_event;
  510. nv.nvEncEncodePicture(enc->session, &params);
  511. get_encoded_packet(enc, true);
  512. }
  513. for (size_t i = 0; i < enc->textures.num; i++) {
  514. nv_texture_free(enc, &enc->textures.array[i]);
  515. }
  516. for (size_t i = 0; i < enc->bitstreams.num; i++) {
  517. nv_bitstream_free(enc, &enc->bitstreams.array[i]);
  518. }
  519. if (enc->session) {
  520. nv.nvEncDestroyEncoder(enc->session);
  521. }
  522. for (size_t i = 0; i < enc->input_textures.num; i++) {
  523. ID3D11Texture2D *tex = enc->input_textures.array[i].tex;
  524. IDXGIKeyedMutex *km = enc->input_textures.array[i].km;
  525. tex->lpVtbl->Release(tex);
  526. km->lpVtbl->Release(km);
  527. }
  528. if (enc->context) {
  529. enc->context->lpVtbl->Release(enc->context);
  530. }
  531. if (enc->device) {
  532. enc->device->lpVtbl->Release(enc->device);
  533. }
  534. bfree(enc->header);
  535. bfree(enc->sei);
  536. circlebuf_free(&enc->dts_list);
  537. da_free(enc->textures);
  538. da_free(enc->bitstreams);
  539. da_free(enc->input_textures);
  540. da_free(enc->packet_data);
  541. bfree(enc);
  542. }
  543. static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc,
  544. uint32_t handle,
  545. IDXGIKeyedMutex **km_out)
  546. {
  547. ID3D11Device *device = enc->device;
  548. IDXGIKeyedMutex *km;
  549. ID3D11Texture2D *input_tex;
  550. HRESULT hr;
  551. for (size_t i = 0; i < enc->input_textures.num; i++) {
  552. struct handle_tex *ht = &enc->input_textures.array[i];
  553. if (ht->handle == handle) {
  554. *km_out = ht->km;
  555. return ht->tex;
  556. }
  557. }
  558. hr = device->lpVtbl->OpenSharedResource(device,
  559. (HANDLE)(uintptr_t)handle,
  560. &IID_ID3D11Texture2D,
  561. &input_tex);
  562. if (FAILED(hr)) {
  563. error_hr("OpenSharedResource failed");
  564. return NULL;
  565. }
  566. hr = input_tex->lpVtbl->QueryInterface(input_tex, &IID_IDXGIKeyedMutex,
  567. &km);
  568. if (FAILED(hr)) {
  569. error_hr("QueryInterface(IDXGIKeyedMutex) failed");
  570. input_tex->lpVtbl->Release(input_tex);
  571. return NULL;
  572. }
  573. input_tex->lpVtbl->SetEvictionPriority(input_tex,
  574. DXGI_RESOURCE_PRIORITY_MAXIMUM);
  575. *km_out = km;
  576. struct handle_tex new_ht = {handle, input_tex, km};
  577. da_push_back(enc->input_textures, &new_ht);
  578. return input_tex;
  579. }
  580. static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
  581. {
  582. void *s = enc->session;
  583. da_resize(enc->packet_data, 0);
  584. if (!enc->buffers_queued)
  585. return true;
  586. if (!finalize && enc->buffers_queued < enc->output_delay)
  587. return true;
  588. size_t count = finalize ? enc->buffers_queued : 1;
  589. for (size_t i = 0; i < count; i++) {
  590. size_t cur_bs_idx = enc->cur_bitstream;
  591. struct nv_bitstream *bs = &enc->bitstreams.array[cur_bs_idx];
  592. struct nv_texture *nvtex = &enc->textures.array[cur_bs_idx];
  593. /* ---------------- */
  594. NV_ENC_LOCK_BITSTREAM lock = {NV_ENC_LOCK_BITSTREAM_VER};
  595. lock.outputBitstream = bs->ptr;
  596. lock.doNotWait = false;
  597. if (NV_FAILED(nv.nvEncLockBitstream(s, &lock))) {
  598. return false;
  599. }
  600. if (enc->first_packet) {
  601. uint8_t *new_packet;
  602. size_t size;
  603. enc->first_packet = false;
  604. obs_extract_avc_headers(lock.bitstreamBufferPtr,
  605. lock.bitstreamSizeInBytes,
  606. &new_packet, &size,
  607. &enc->header, &enc->header_size,
  608. &enc->sei, &enc->sei_size);
  609. da_copy_array(enc->packet_data, new_packet, size);
  610. bfree(new_packet);
  611. } else {
  612. da_copy_array(enc->packet_data, lock.bitstreamBufferPtr,
  613. lock.bitstreamSizeInBytes);
  614. }
  615. enc->packet_pts = (int64_t)lock.outputTimeStamp;
  616. enc->packet_keyframe = lock.pictureType == NV_ENC_PIC_TYPE_IDR;
  617. if (NV_FAILED(nv.nvEncUnlockBitstream(s, bs->ptr))) {
  618. return false;
  619. }
  620. /* ---------------- */
  621. if (nvtex->mapped_res) {
  622. NVENCSTATUS err;
  623. err = nv.nvEncUnmapInputResource(s, nvtex->mapped_res);
  624. if (nv_failed(enc->encoder, err, __FUNCTION__,
  625. "unmap")) {
  626. return false;
  627. }
  628. nvtex->mapped_res = NULL;
  629. }
  630. /* ---------------- */
  631. if (++enc->cur_bitstream == enc->buf_count)
  632. enc->cur_bitstream = 0;
  633. enc->buffers_queued--;
  634. }
  635. return true;
  636. }
  637. static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
  638. uint64_t lock_key, uint64_t *next_key,
  639. struct encoder_packet *packet,
  640. bool *received_packet)
  641. {
  642. struct nvenc_data *enc = data;
  643. ID3D11Device *device = enc->device;
  644. ID3D11DeviceContext *context = enc->context;
  645. ID3D11Texture2D *input_tex;
  646. ID3D11Texture2D *output_tex;
  647. IDXGIKeyedMutex *km;
  648. struct nv_texture *nvtex;
  649. struct nv_bitstream *bs;
  650. NVENCSTATUS err;
  651. if (handle == GS_INVALID_HANDLE) {
  652. error("Encode failed: bad texture handle");
  653. *next_key = lock_key;
  654. return false;
  655. }
  656. bs = &enc->bitstreams.array[enc->next_bitstream];
  657. nvtex = &enc->textures.array[enc->next_bitstream];
  658. input_tex = get_tex_from_handle(enc, handle, &km);
  659. output_tex = nvtex->tex;
  660. if (!input_tex) {
  661. *next_key = lock_key;
  662. return false;
  663. }
  664. circlebuf_push_back(&enc->dts_list, &pts, sizeof(pts));
  665. /* ------------------------------------ */
  666. /* wait for output bitstream/tex */
  667. WaitForSingleObject(bs->event, INFINITE);
  668. /* ------------------------------------ */
  669. /* copy to output tex */
  670. km->lpVtbl->AcquireSync(km, lock_key, INFINITE);
  671. context->lpVtbl->CopyResource(context, (ID3D11Resource *)output_tex,
  672. (ID3D11Resource *)input_tex);
  673. km->lpVtbl->ReleaseSync(km, *next_key);
  674. /* ------------------------------------ */
  675. /* map output tex so nvenc can use it */
  676. NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
  677. map.registeredResource = nvtex->res;
  678. if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map))) {
  679. return false;
  680. }
  681. nvtex->mapped_res = map.mappedResource;
  682. /* ------------------------------------ */
  683. /* do actual encode call */
  684. NV_ENC_PIC_PARAMS params = {0};
  685. params.version = NV_ENC_PIC_PARAMS_VER;
  686. params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
  687. params.inputBuffer = nvtex->mapped_res;
  688. params.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
  689. params.inputTimeStamp = (uint64_t)pts;
  690. params.inputWidth = enc->cx;
  691. params.inputHeight = enc->cy;
  692. params.outputBitstream = bs->ptr;
  693. params.completionEvent = bs->event;
  694. err = nv.nvEncEncodePicture(enc->session, &params);
  695. if (err != NV_ENC_SUCCESS && err != NV_ENC_ERR_NEED_MORE_INPUT) {
  696. nv_failed(enc->encoder, err, __FUNCTION__,
  697. "nvEncEncodePicture");
  698. return false;
  699. }
  700. enc->encode_started = true;
  701. enc->buffers_queued++;
  702. if (++enc->next_bitstream == enc->buf_count) {
  703. enc->next_bitstream = 0;
  704. }
  705. /* ------------------------------------ */
  706. /* check for encoded packet and parse */
  707. if (!get_encoded_packet(enc, false)) {
  708. return false;
  709. }
  710. /* ------------------------------------ */
  711. /* output encoded packet */
  712. if (enc->packet_data.num) {
  713. int64_t dts;
  714. circlebuf_pop_front(&enc->dts_list, &dts, sizeof(dts));
  715. /* subtract bframe delay from dts */
  716. if (enc->bframes)
  717. dts -= packet->timebase_num;
  718. *received_packet = true;
  719. packet->data = enc->packet_data.array;
  720. packet->size = enc->packet_data.num;
  721. packet->type = OBS_ENCODER_VIDEO;
  722. packet->pts = enc->packet_pts;
  723. packet->dts = dts;
  724. packet->keyframe = enc->packet_keyframe;
  725. } else {
  726. *received_packet = false;
  727. }
  728. return true;
  729. }
  730. extern void nvenc_defaults(obs_data_t *settings);
  731. extern obs_properties_t *nvenc_properties(void *unused);
  732. static bool nvenc_extra_data(void *data, uint8_t **header, size_t *size)
  733. {
  734. struct nvenc_data *enc = data;
  735. if (!enc->header) {
  736. return false;
  737. }
  738. *header = enc->header;
  739. *size = enc->header_size;
  740. return true;
  741. }
  742. static bool nvenc_sei_data(void *data, uint8_t **sei, size_t *size)
  743. {
  744. struct nvenc_data *enc = data;
  745. if (!enc->sei) {
  746. return false;
  747. }
  748. *sei = enc->sei;
  749. *size = enc->sei_size;
  750. return true;
  751. }
  752. struct obs_encoder_info nvenc_info = {
  753. .id = "jim_nvenc",
  754. .codec = "h264",
  755. .type = OBS_ENCODER_VIDEO,
  756. .caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE,
  757. .get_name = nvenc_get_name,
  758. .create = nvenc_create,
  759. .destroy = nvenc_destroy,
  760. .update = nvenc_update,
  761. .encode_texture = nvenc_encode_tex,
  762. .get_defaults = nvenc_defaults,
  763. .get_properties = nvenc_properties,
  764. .get_extra_data = nvenc_extra_data,
  765. .get_sei_data = nvenc_sei_data,
  766. };