jim-nvenc.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  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) \
  20. error("%s: %s: 0x%08lX", __FUNCTION__, msg, (uint32_t)hr);
  21. struct nv_bitstream;
  22. struct nv_texture;
  23. struct handle_tex {
  24. uint32_t handle;
  25. ID3D11Texture2D *tex;
  26. IDXGIKeyedMutex *km;
  27. };
  28. /* ------------------------------------------------------------------------- */
  29. /* Main Implementation Structure */
  30. struct nvenc_data {
  31. obs_encoder_t *encoder;
  32. void *session;
  33. NV_ENC_INITIALIZE_PARAMS params;
  34. NV_ENC_CONFIG config;
  35. size_t buf_count;
  36. size_t output_delay;
  37. size_t buffers_queued;
  38. size_t next_bitstream;
  39. size_t cur_bitstream;
  40. bool encode_started;
  41. bool first_packet;
  42. bool can_change_bitrate;
  43. bool bframes;
  44. DARRAY(struct nv_bitstream) bitstreams;
  45. DARRAY(struct nv_texture) textures;
  46. DARRAY(struct handle_tex) input_textures;
  47. struct circlebuf dts_list;
  48. DARRAY(uint8_t) packet_data;
  49. int64_t packet_pts;
  50. bool packet_keyframe;
  51. ID3D11Device *device;
  52. ID3D11DeviceContext *context;
  53. uint32_t cx;
  54. uint32_t cy;
  55. uint8_t *header;
  56. size_t header_size;
  57. uint8_t *sei;
  58. size_t sei_size;
  59. };
  60. /* ------------------------------------------------------------------------- */
  61. /* Bitstream Buffer */
  62. struct nv_bitstream {
  63. void *ptr;
  64. HANDLE event;
  65. };
  66. static inline bool nv_failed(struct nvenc_data *enc, NVENCSTATUS err,
  67. const char *func, const char *call)
  68. {
  69. if (err == NV_ENC_SUCCESS)
  70. return false;
  71. error("%s: %s failed: %d (%s)", func, call, (int)err,
  72. nv_error_name(err));
  73. return true;
  74. }
  75. #define NV_FAILED(x) nv_failed(enc, x, __FUNCTION__, #x)
  76. static bool nv_bitstream_init(struct nvenc_data *enc, struct nv_bitstream *bs)
  77. {
  78. NV_ENC_CREATE_BITSTREAM_BUFFER buf = {NV_ENC_CREATE_BITSTREAM_BUFFER_VER};
  79. NV_ENC_EVENT_PARAMS params = {NV_ENC_EVENT_PARAMS_VER};
  80. HANDLE event = NULL;
  81. if (NV_FAILED(nv.nvEncCreateBitstreamBuffer(enc->session, &buf))) {
  82. return false;
  83. }
  84. event = CreateEvent(NULL, true, true, NULL);
  85. if (!event) {
  86. error("%s: %s", __FUNCTION__, "Failed to create event");
  87. goto fail;
  88. }
  89. params.completionEvent = event;
  90. if (NV_FAILED(nv.nvEncRegisterAsyncEvent(enc->session, &params))) {
  91. goto fail;
  92. }
  93. bs->ptr = buf.bitstreamBuffer;
  94. bs->event = event;
  95. return true;
  96. fail:
  97. if (event) {
  98. CloseHandle(event);
  99. }
  100. if (buf.bitstreamBuffer) {
  101. nv.nvEncDestroyBitstreamBuffer(enc->session,
  102. buf.bitstreamBuffer);
  103. }
  104. return false;
  105. }
  106. static void nv_bitstream_free(struct nvenc_data *enc, struct nv_bitstream *bs)
  107. {
  108. if (bs->ptr) {
  109. nv.nvEncDestroyBitstreamBuffer(enc->session, bs->ptr);
  110. NV_ENC_EVENT_PARAMS params = {NV_ENC_EVENT_PARAMS_VER};
  111. params.completionEvent = bs->event;
  112. nv.nvEncUnregisterAsyncEvent(enc->session, &params);
  113. CloseHandle(bs->event);
  114. }
  115. }
  116. /* ------------------------------------------------------------------------- */
  117. /* Texture Resource */
  118. struct nv_texture {
  119. void *res;
  120. ID3D11Texture2D *tex;
  121. void *mapped_res;
  122. };
  123. static bool nv_texture_init(struct nvenc_data *enc, struct nv_texture *nvtex)
  124. {
  125. ID3D11Device *device = enc->device;
  126. ID3D11Texture2D *tex;
  127. HRESULT hr;
  128. D3D11_TEXTURE2D_DESC desc = {0};
  129. desc.Width = enc->cx;
  130. desc.Height = enc->cy;
  131. desc.MipLevels = 1;
  132. desc.ArraySize = 1;
  133. desc.Format = DXGI_FORMAT_NV12;
  134. desc.SampleDesc.Count = 1;
  135. desc.BindFlags = D3D11_BIND_RENDER_TARGET;
  136. hr = device->lpVtbl->CreateTexture2D(device, &desc, NULL, &tex);
  137. if (FAILED(hr)) {
  138. error_hr("Failed to create texture");
  139. return false;
  140. }
  141. tex->lpVtbl->SetEvictionPriority(tex, DXGI_RESOURCE_PRIORITY_MAXIMUM);
  142. NV_ENC_REGISTER_RESOURCE res = {NV_ENC_REGISTER_RESOURCE_VER};
  143. res.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
  144. res.resourceToRegister = tex;
  145. res.width = enc->cx;
  146. res.height = enc->cy;
  147. res.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
  148. if (NV_FAILED(nv.nvEncRegisterResource(enc->session, &res))) {
  149. tex->lpVtbl->Release(tex);
  150. return false;
  151. }
  152. nvtex->res = res.registeredResource;
  153. nvtex->tex = tex;
  154. return true;
  155. }
  156. static void nv_texture_free(struct nvenc_data *enc, struct nv_texture *nvtex)
  157. {
  158. if (nvtex->res) {
  159. if (nvtex->mapped_res) {
  160. nv.nvEncUnmapInputResource(enc->session,
  161. nvtex->mapped_res);
  162. }
  163. nv.nvEncUnregisterResource(enc->session, nvtex->res);
  164. nvtex->tex->lpVtbl->Release(nvtex->tex);
  165. }
  166. }
  167. /* ------------------------------------------------------------------------- */
  168. /* Implementation */
  169. static const char *nvenc_get_name(void *type_data)
  170. {
  171. UNUSED_PARAMETER(type_data);
  172. return "NVIDIA NVENC H.264 (new)";
  173. }
  174. static inline int nv_get_cap(struct nvenc_data *enc, NV_ENC_CAPS cap)
  175. {
  176. if (!enc->session)
  177. return 0;
  178. NV_ENC_CAPS_PARAM param = {NV_ENC_CAPS_PARAM_VER};
  179. int v;
  180. param.capsToQuery = cap;
  181. nv.nvEncGetEncodeCaps(enc->session, NV_ENC_CODEC_H264_GUID, &param, &v);
  182. return v;
  183. }
  184. static bool nvenc_update(void *data, obs_data_t *settings)
  185. {
  186. struct nvenc_data *enc = data;
  187. /* Only support reconfiguration of CBR bitrate */
  188. if (enc->can_change_bitrate) {
  189. int bitrate = (int)obs_data_get_int(settings, "bitrate");
  190. enc->config.rcParams.averageBitRate = bitrate * 1000;
  191. enc->config.rcParams.maxBitRate = bitrate * 1000;
  192. NV_ENC_RECONFIGURE_PARAMS params = {0};
  193. params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
  194. params.reInitEncodeParams = enc->params;
  195. if (FAILED(nv.nvEncReconfigureEncoder(enc->session, &params))) {
  196. return false;
  197. }
  198. }
  199. return true;
  200. }
  201. static HANDLE get_lib(struct nvenc_data *enc, const char *lib)
  202. {
  203. HMODULE mod = GetModuleHandleA(lib);
  204. if (mod)
  205. return mod;
  206. mod = LoadLibraryA(lib);
  207. if (!mod)
  208. error("Failed to load %s", lib);
  209. return mod;
  210. }
  211. typedef HRESULT (WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
  212. static bool init_d3d11(struct nvenc_data *enc, obs_data_t *settings)
  213. {
  214. HMODULE dxgi = get_lib(enc, "DXGI.dll");
  215. HMODULE d3d11 = get_lib(enc, "D3D11.dll");
  216. CREATEDXGIFACTORY1PROC create_dxgi;
  217. PFN_D3D11_CREATE_DEVICE create_device;
  218. IDXGIFactory1 *factory;
  219. IDXGIAdapter *adapter;
  220. ID3D11Device *device;
  221. ID3D11DeviceContext *context;
  222. HRESULT hr;
  223. if (!dxgi || !d3d11) {
  224. return false;
  225. }
  226. create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress(dxgi,
  227. "CreateDXGIFactory1");
  228. create_device = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11,
  229. "D3D11CreateDevice");
  230. if (!create_dxgi || !create_device) {
  231. error("Failed to load D3D11/DXGI procedures");
  232. return false;
  233. }
  234. hr = create_dxgi(&IID_IDXGIFactory1, &factory);
  235. if (FAILED(hr)) {
  236. error_hr("CreateDXGIFactory1 failed");
  237. return false;
  238. }
  239. hr = factory->lpVtbl->EnumAdapters(factory, 0, &adapter);
  240. factory->lpVtbl->Release(factory);
  241. if (FAILED(hr)) {
  242. error_hr("EnumAdapters failed");
  243. return false;
  244. }
  245. hr = create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0,
  246. NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context);
  247. adapter->lpVtbl->Release(adapter);
  248. if (FAILED(hr)) {
  249. error_hr("D3D11CreateDevice failed");
  250. return false;
  251. }
  252. enc->device = device;
  253. enc->context = context;
  254. return true;
  255. }
  256. static bool init_session(struct nvenc_data *enc)
  257. {
  258. NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params =
  259. {NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER};
  260. params.device = enc->device;
  261. params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
  262. params.apiVersion = NVENCAPI_VERSION;
  263. if (NV_FAILED(nv.nvEncOpenEncodeSessionEx(&params, &enc->session))) {
  264. return false;
  265. }
  266. return true;
  267. }
  268. static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
  269. {
  270. const char *rc = obs_data_get_string(settings, "rate_control");
  271. int bitrate = (int)obs_data_get_int(settings, "bitrate");
  272. int max_bitrate = (int)obs_data_get_int(settings, "max_bitrate");
  273. int cqp = (int)obs_data_get_int(settings, "cqp");
  274. int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
  275. const char *preset = obs_data_get_string(settings, "preset");
  276. const char *profile = obs_data_get_string(settings, "profile");
  277. bool psycho_aq = obs_data_get_bool(settings, "psycho_aq");
  278. bool lookahead = obs_data_get_bool(settings, "lookahead");
  279. int bf = (int)obs_data_get_int(settings, "bf");
  280. bool vbr = astrcmpi(rc, "VBR") == 0;
  281. NVENCSTATUS err;
  282. video_t *video = obs_encoder_video(enc->encoder);
  283. const struct video_output_info *voi = video_output_get_info(video);
  284. enc->cx = voi->width;
  285. enc->cy = voi->height;
  286. /* -------------------------- */
  287. /* get preset */
  288. GUID nv_preset = NV_ENC_PRESET_DEFAULT_GUID;
  289. bool twopass = false;
  290. bool hp = false;
  291. bool ll = false;
  292. if (astrcmpi(preset, "hq") == 0) {
  293. nv_preset = NV_ENC_PRESET_HQ_GUID;
  294. } else if (astrcmpi(preset, "mq") == 0) {
  295. nv_preset = NV_ENC_PRESET_HQ_GUID;
  296. twopass = true;
  297. } else if (astrcmpi(preset, "hp") == 0) {
  298. nv_preset = NV_ENC_PRESET_HP_GUID;
  299. hp = true;
  300. } else if (astrcmpi(preset, "ll") == 0) {
  301. nv_preset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
  302. ll = true;
  303. } else if (astrcmpi(preset, "llhq") == 0) {
  304. nv_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
  305. ll = true;
  306. } else if (astrcmpi(preset, "llhp") == 0) {
  307. nv_preset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
  308. hp = true;
  309. ll = true;
  310. }
  311. if (astrcmpi(rc, "lossless") == 0) {
  312. nv_preset = hp
  313. ? NV_ENC_PRESET_LOSSLESS_HP_GUID
  314. : NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
  315. }
  316. /* -------------------------- */
  317. /* get preset default config */
  318. NV_ENC_PRESET_CONFIG preset_config =
  319. {NV_ENC_PRESET_CONFIG_VER, {NV_ENC_CONFIG_VER}};
  320. err = nv.nvEncGetEncodePresetConfig(enc->session,
  321. NV_ENC_CODEC_H264_GUID, nv_preset, &preset_config);
  322. if (nv_failed(enc, err, __FUNCTION__, "nvEncGetEncodePresetConfig")) {
  323. return false;
  324. }
  325. /* -------------------------- */
  326. /* main configuration */
  327. enc->config = preset_config.presetCfg;
  328. uint32_t gop_size = (keyint_sec)
  329. ? keyint_sec * voi->fps_num / voi->fps_den
  330. : 250;
  331. NV_ENC_INITIALIZE_PARAMS *params = &enc->params;
  332. NV_ENC_CONFIG *config = &enc->config;
  333. NV_ENC_CONFIG_H264 *h264_config = &config->encodeCodecConfig.h264Config;
  334. NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui_params =
  335. &h264_config->h264VUIParameters;
  336. memset(params, 0, sizeof(*params));
  337. params->version = NV_ENC_INITIALIZE_PARAMS_VER;
  338. params->encodeGUID = NV_ENC_CODEC_H264_GUID;
  339. params->presetGUID = nv_preset;
  340. params->encodeWidth = voi->width;
  341. params->encodeHeight = voi->height;
  342. params->darWidth = voi->width;
  343. params->darHeight = voi->height;
  344. params->frameRateNum = voi->fps_num;
  345. params->frameRateDen = voi->fps_den;
  346. params->enableEncodeAsync = 1;
  347. params->enablePTD = 1;
  348. params->encodeConfig = &enc->config;
  349. params->maxEncodeWidth = voi->width;
  350. params->maxEncodeHeight = voi->height;
  351. config->gopLength = gop_size;
  352. config->frameIntervalP = 1 + bf;
  353. h264_config->idrPeriod = gop_size;
  354. vui_params->videoSignalTypePresentFlag = 1;
  355. vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
  356. vui_params->colourDescriptionPresentFlag = 1;
  357. vui_params->colourMatrix = (voi->colorspace == VIDEO_CS_709) ? 1 : 5;
  358. vui_params->colourPrimaries = 1;
  359. vui_params->transferCharacteristics = 1;
  360. enc->bframes = bf > 0;
  361. /* lookahead */
  362. if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) {
  363. config->rcParams.lookaheadDepth = 8;
  364. config->rcParams.enableLookahead = 1;
  365. }
  366. /* psycho aq */
  367. if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) {
  368. config->rcParams.enableAQ = psycho_aq;
  369. config->rcParams.enableTemporalAQ = psycho_aq;
  370. }
  371. /* -------------------------- */
  372. /* rate control */
  373. enc->can_change_bitrate =
  374. nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
  375. config->rcParams.rateControlMode = twopass
  376. ? NV_ENC_PARAMS_RC_VBR_HQ
  377. : NV_ENC_PARAMS_RC_VBR;
  378. if (astrcmpi(rc, "cqp") == 0 || astrcmpi(rc, "lossless") == 0) {
  379. if (astrcmpi(rc, "lossless") == 0)
  380. cqp = 0;
  381. config->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
  382. config->rcParams.constQP.qpInterP = cqp;
  383. config->rcParams.constQP.qpInterB = cqp;
  384. config->rcParams.constQP.qpIntra = cqp;
  385. enc->can_change_bitrate = false;
  386. bitrate = 0;
  387. max_bitrate = 0;
  388. } else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
  389. h264_config->outputBufferingPeriodSEI = 1;
  390. config->rcParams.rateControlMode = twopass
  391. ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
  392. : NV_ENC_PARAMS_RC_CBR;
  393. }
  394. h264_config->outputPictureTimingSEI = 1;
  395. config->rcParams.averageBitRate = bitrate * 1000;
  396. config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
  397. /* -------------------------- */
  398. /* profile */
  399. if (astrcmpi(profile, "main") == 0) {
  400. config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
  401. } else if (astrcmpi(profile, "baseline") == 0) {
  402. config->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
  403. } else {
  404. config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
  405. }
  406. /* -------------------------- */
  407. /* initialize */
  408. if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, params))) {
  409. return false;
  410. }
  411. enc->buf_count = config->frameIntervalP +
  412. config->rcParams.lookaheadDepth + EXTRA_BUFFERS;
  413. enc->output_delay = enc->buf_count - 1;
  414. info("settings:\n"
  415. "\trate_control: %s\n"
  416. "\tbitrate: %d\n"
  417. "\tcqp: %d\n"
  418. "\tkeyint: %d\n"
  419. "\tpreset: %s\n"
  420. "\tprofile: %s\n"
  421. "\twidth: %d\n"
  422. "\theight: %d\n"
  423. "\t2-pass: %s\n"
  424. "\tb-frames: %d\n"
  425. "\tlookahead: %s\n"
  426. "\tpsycho_aq: %s\n",
  427. rc, bitrate, cqp, gop_size,
  428. preset, profile,
  429. enc->cx, enc->cy,
  430. twopass ? "true" : "false",
  431. bf,
  432. lookahead ? "true" : "false",
  433. psycho_aq ? "true" : "false");
  434. return true;
  435. }
  436. static bool init_bitstreams(struct nvenc_data *enc)
  437. {
  438. da_reserve(enc->bitstreams, enc->buf_count);
  439. for (size_t i = 0; i < enc->buf_count; i++) {
  440. struct nv_bitstream bitstream;
  441. if (!nv_bitstream_init(enc, &bitstream)) {
  442. return false;
  443. }
  444. da_push_back(enc->bitstreams, &bitstream);
  445. }
  446. return true;
  447. }
  448. static bool init_textures(struct nvenc_data *enc)
  449. {
  450. da_reserve(enc->bitstreams, enc->buf_count);
  451. for (size_t i = 0; i < enc->buf_count; i++) {
  452. struct nv_texture texture;
  453. if (!nv_texture_init(enc, &texture)) {
  454. return false;
  455. }
  456. da_push_back(enc->textures, &texture);
  457. }
  458. return true;
  459. }
  460. static void nvenc_destroy(void *data);
  461. static void *nvenc_create(obs_data_t *settings, obs_encoder_t *encoder)
  462. {
  463. NV_ENCODE_API_FUNCTION_LIST init = {NV_ENCODE_API_FUNCTION_LIST_VER};
  464. struct nvenc_data *enc = bzalloc(sizeof(*enc));
  465. enc->encoder = encoder;
  466. enc->first_packet = true;
  467. /* this encoder requires shared textures, this cannot be used on a
  468. * gpu other than the one OBS is currently running on. */
  469. int gpu = (int)obs_data_get_int(settings, "gpu");
  470. if (gpu != 0) {
  471. goto fail;
  472. }
  473. if (!obs_nv12_tex_active()) {
  474. goto fail;
  475. }
  476. if (!init_nvenc()) {
  477. goto fail;
  478. }
  479. if (NV_FAILED(nv_create_instance(&init))) {
  480. goto fail;
  481. }
  482. if (!init_d3d11(enc, settings)) {
  483. goto fail;
  484. }
  485. if (!init_session(enc)) {
  486. goto fail;
  487. }
  488. if (!init_encoder(enc, settings)) {
  489. goto fail;
  490. }
  491. if (!init_bitstreams(enc)) {
  492. goto fail;
  493. }
  494. if (!init_textures(enc)) {
  495. goto fail;
  496. }
  497. return enc;
  498. fail:
  499. nvenc_destroy(enc);
  500. return obs_encoder_create_rerouted(encoder, "ffmpeg_nvenc");
  501. }
  502. static bool get_encoded_packet(struct nvenc_data *enc, bool finalize);
  503. static void nvenc_destroy(void *data)
  504. {
  505. struct nvenc_data *enc = data;
  506. if (enc->encode_started) {
  507. size_t next_bitstream = enc->next_bitstream;
  508. HANDLE next_event = enc->bitstreams.array[next_bitstream].event;
  509. NV_ENC_PIC_PARAMS params = {NV_ENC_PIC_PARAMS_VER};
  510. params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
  511. params.completionEvent = next_event;
  512. nv.nvEncEncodePicture(enc->session, &params);
  513. get_encoded_packet(enc, true);
  514. }
  515. for (size_t i = 0; i < enc->textures.num; i++) {
  516. nv_texture_free(enc, &enc->textures.array[i]);
  517. }
  518. for (size_t i = 0; i < enc->bitstreams.num; i++) {
  519. nv_bitstream_free(enc, &enc->bitstreams.array[i]);
  520. }
  521. if (enc->session) {
  522. nv.nvEncDestroyEncoder(enc->session);
  523. }
  524. for (size_t i = 0; i < enc->input_textures.num; i++) {
  525. ID3D11Texture2D *tex = enc->input_textures.array[i].tex;
  526. IDXGIKeyedMutex *km = enc->input_textures.array[i].km;
  527. tex->lpVtbl->Release(tex);
  528. km->lpVtbl->Release(km);
  529. }
  530. if (enc->context) {
  531. enc->context->lpVtbl->Release(enc->context);
  532. }
  533. if (enc->device) {
  534. enc->device->lpVtbl->Release(enc->device);
  535. }
  536. bfree(enc->header);
  537. bfree(enc->sei);
  538. circlebuf_free(&enc->dts_list);
  539. da_free(enc->textures);
  540. da_free(enc->bitstreams);
  541. da_free(enc->input_textures);
  542. da_free(enc->packet_data);
  543. bfree(enc);
  544. }
  545. static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc,
  546. uint32_t handle, IDXGIKeyedMutex **km_out)
  547. {
  548. ID3D11Device *device = enc->device;
  549. IDXGIKeyedMutex *km;
  550. ID3D11Texture2D *input_tex;
  551. HRESULT hr;
  552. for (size_t i = 0; i < enc->input_textures.num; i++) {
  553. struct handle_tex *ht = &enc->input_textures.array[i];
  554. if (ht->handle == handle) {
  555. *km_out = ht->km;
  556. return ht->tex;
  557. }
  558. }
  559. hr = device->lpVtbl->OpenSharedResource(device,
  560. (HANDLE)(uintptr_t)handle,
  561. &IID_ID3D11Texture2D, &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(
  605. lock.bitstreamBufferPtr,
  606. lock.bitstreamSizeInBytes,
  607. &new_packet, &size,
  608. &enc->header, &enc->header_size,
  609. &enc->sei, &enc->sei_size);
  610. da_copy_array(enc->packet_data, new_packet, size);
  611. bfree(new_packet);
  612. } else {
  613. da_copy_array(enc->packet_data,
  614. lock.bitstreamBufferPtr,
  615. lock.bitstreamSizeInBytes);
  616. }
  617. enc->packet_pts = (int64_t)lock.outputTimeStamp;
  618. enc->packet_keyframe = lock.pictureType == NV_ENC_PIC_TYPE_IDR;
  619. if (NV_FAILED(nv.nvEncUnlockBitstream(s, bs->ptr))) {
  620. return false;
  621. }
  622. /* ---------------- */
  623. if (nvtex->mapped_res) {
  624. NVENCSTATUS err;
  625. err = nv.nvEncUnmapInputResource(s, nvtex->mapped_res);
  626. if (nv_failed(enc, err, __FUNCTION__, "unmap")) {
  627. return false;
  628. }
  629. nvtex->mapped_res = NULL;
  630. }
  631. /* ---------------- */
  632. if (++enc->cur_bitstream == enc->buf_count)
  633. enc->cur_bitstream = 0;
  634. enc->buffers_queued--;
  635. }
  636. return true;
  637. }
  638. static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
  639. uint64_t lock_key, uint64_t *next_key,
  640. struct encoder_packet *packet, 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,
  672. (ID3D11Resource *)output_tex,
  673. (ID3D11Resource *)input_tex);
  674. km->lpVtbl->ReleaseSync(km, *next_key);
  675. /* ------------------------------------ */
  676. /* map output tex so nvenc can use it */
  677. NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
  678. map.registeredResource = nvtex->res;
  679. if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map))) {
  680. return false;
  681. }
  682. nvtex->mapped_res = map.mappedResource;
  683. /* ------------------------------------ */
  684. /* do actual encode call */
  685. NV_ENC_PIC_PARAMS params = {0};
  686. params.version = NV_ENC_PIC_PARAMS_VER;
  687. params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
  688. params.inputBuffer = nvtex->mapped_res;
  689. params.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
  690. params.inputTimeStamp = (uint64_t)pts;
  691. params.inputWidth = enc->cx;
  692. params.inputHeight = enc->cy;
  693. params.outputBitstream = bs->ptr;
  694. params.completionEvent = bs->event;
  695. err = nv.nvEncEncodePicture(enc->session, &params);
  696. if (err != NV_ENC_SUCCESS && err != NV_ENC_ERR_NEED_MORE_INPUT) {
  697. nv_failed(enc, err, __FUNCTION__, "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--;
  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,
  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. };