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) 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. static inline bool nv_failed(struct nvenc_data *enc, NVENCSTATUS err,
  66. const char *func, const char *call)
  67. {
  68. if (err == NV_ENC_SUCCESS)
  69. return false;
  70. error("%s: %s failed: %d (%s)", func, call, (int)err,
  71. nv_error_name(err));
  72. return true;
  73. }
  74. #define NV_FAILED(x) nv_failed(enc, x, __FUNCTION__, #x)
  75. static bool nv_bitstream_init(struct nvenc_data *enc, struct nv_bitstream *bs)
  76. {
  77. NV_ENC_CREATE_BITSTREAM_BUFFER buf = {
  78. 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. params.resetEncoder = 1;
  196. params.forceIDR = 1;
  197. if (NV_FAILED(nv.nvEncReconfigureEncoder(enc->session,
  198. &params))) {
  199. return false;
  200. }
  201. }
  202. return true;
  203. }
  204. static HANDLE get_lib(struct nvenc_data *enc, const char *lib)
  205. {
  206. HMODULE mod = GetModuleHandleA(lib);
  207. if (mod)
  208. return mod;
  209. mod = LoadLibraryA(lib);
  210. if (!mod)
  211. error("Failed to load %s", lib);
  212. return mod;
  213. }
  214. typedef HRESULT(WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
  215. static bool init_d3d11(struct nvenc_data *enc, obs_data_t *settings)
  216. {
  217. HMODULE dxgi = get_lib(enc, "DXGI.dll");
  218. HMODULE d3d11 = get_lib(enc, "D3D11.dll");
  219. CREATEDXGIFACTORY1PROC create_dxgi;
  220. PFN_D3D11_CREATE_DEVICE create_device;
  221. IDXGIFactory1 *factory;
  222. IDXGIAdapter *adapter;
  223. ID3D11Device *device;
  224. ID3D11DeviceContext *context;
  225. HRESULT hr;
  226. if (!dxgi || !d3d11) {
  227. return false;
  228. }
  229. create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress(
  230. dxgi, "CreateDXGIFactory1");
  231. create_device = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(
  232. d3d11, "D3D11CreateDevice");
  233. if (!create_dxgi || !create_device) {
  234. error("Failed to load D3D11/DXGI procedures");
  235. return false;
  236. }
  237. hr = create_dxgi(&IID_IDXGIFactory1, &factory);
  238. if (FAILED(hr)) {
  239. error_hr("CreateDXGIFactory1 failed");
  240. return false;
  241. }
  242. hr = factory->lpVtbl->EnumAdapters(factory, 0, &adapter);
  243. factory->lpVtbl->Release(factory);
  244. if (FAILED(hr)) {
  245. error_hr("EnumAdapters failed");
  246. return false;
  247. }
  248. hr = create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0,
  249. D3D11_SDK_VERSION, &device, NULL, &context);
  250. adapter->lpVtbl->Release(adapter);
  251. if (FAILED(hr)) {
  252. error_hr("D3D11CreateDevice failed");
  253. return false;
  254. }
  255. enc->device = device;
  256. enc->context = context;
  257. return true;
  258. }
  259. static bool init_session(struct nvenc_data *enc)
  260. {
  261. NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = {
  262. NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER};
  263. params.device = enc->device;
  264. params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
  265. params.apiVersion = NVENCAPI_VERSION;
  266. if (NV_FAILED(nv.nvEncOpenEncodeSessionEx(&params, &enc->session))) {
  267. return false;
  268. }
  269. return true;
  270. }
  271. static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
  272. {
  273. const char *rc = obs_data_get_string(settings, "rate_control");
  274. int bitrate = (int)obs_data_get_int(settings, "bitrate");
  275. int max_bitrate = (int)obs_data_get_int(settings, "max_bitrate");
  276. int cqp = (int)obs_data_get_int(settings, "cqp");
  277. int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
  278. const char *preset = obs_data_get_string(settings, "preset");
  279. const char *profile = obs_data_get_string(settings, "profile");
  280. bool psycho_aq = obs_data_get_bool(settings, "psycho_aq");
  281. bool lookahead = obs_data_get_bool(settings, "lookahead");
  282. int bf = (int)obs_data_get_int(settings, "bf");
  283. bool vbr = astrcmpi(rc, "VBR") == 0;
  284. NVENCSTATUS err;
  285. video_t *video = obs_encoder_video(enc->encoder);
  286. const struct video_output_info *voi = video_output_get_info(video);
  287. enc->cx = voi->width;
  288. enc->cy = voi->height;
  289. /* -------------------------- */
  290. /* get preset */
  291. GUID nv_preset = NV_ENC_PRESET_DEFAULT_GUID;
  292. bool twopass = false;
  293. bool hp = false;
  294. bool ll = false;
  295. if (astrcmpi(preset, "hq") == 0) {
  296. nv_preset = NV_ENC_PRESET_HQ_GUID;
  297. } else if (astrcmpi(preset, "mq") == 0) {
  298. nv_preset = NV_ENC_PRESET_HQ_GUID;
  299. twopass = true;
  300. } else if (astrcmpi(preset, "hp") == 0) {
  301. nv_preset = NV_ENC_PRESET_HP_GUID;
  302. hp = true;
  303. } else if (astrcmpi(preset, "ll") == 0) {
  304. nv_preset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
  305. ll = true;
  306. } else if (astrcmpi(preset, "llhq") == 0) {
  307. nv_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
  308. ll = true;
  309. } else if (astrcmpi(preset, "llhp") == 0) {
  310. nv_preset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
  311. hp = true;
  312. ll = true;
  313. }
  314. if (astrcmpi(rc, "lossless") == 0) {
  315. nv_preset = hp ? NV_ENC_PRESET_LOSSLESS_HP_GUID
  316. : NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
  317. }
  318. /* -------------------------- */
  319. /* get preset default config */
  320. NV_ENC_PRESET_CONFIG preset_config = {NV_ENC_PRESET_CONFIG_VER,
  321. {NV_ENC_CONFIG_VER}};
  322. err = nv.nvEncGetEncodePresetConfig(enc->session,
  323. NV_ENC_CODEC_H264_GUID, nv_preset,
  324. &preset_config);
  325. if (nv_failed(enc, err, __FUNCTION__, "nvEncGetEncodePresetConfig")) {
  326. return false;
  327. }
  328. /* -------------------------- */
  329. /* main configuration */
  330. enc->config = preset_config.presetCfg;
  331. uint32_t gop_size =
  332. (keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
  333. NV_ENC_INITIALIZE_PARAMS *params = &enc->params;
  334. NV_ENC_CONFIG *config = &enc->config;
  335. NV_ENC_CONFIG_H264 *h264_config = &config->encodeCodecConfig.h264Config;
  336. NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui_params =
  337. &h264_config->h264VUIParameters;
  338. memset(params, 0, sizeof(*params));
  339. params->version = NV_ENC_INITIALIZE_PARAMS_VER;
  340. params->encodeGUID = NV_ENC_CODEC_H264_GUID;
  341. params->presetGUID = nv_preset;
  342. params->encodeWidth = voi->width;
  343. params->encodeHeight = voi->height;
  344. params->darWidth = voi->width;
  345. params->darHeight = voi->height;
  346. params->frameRateNum = voi->fps_num;
  347. params->frameRateDen = voi->fps_den;
  348. params->enableEncodeAsync = 1;
  349. params->enablePTD = 1;
  350. params->encodeConfig = &enc->config;
  351. params->maxEncodeWidth = voi->width;
  352. params->maxEncodeHeight = voi->height;
  353. config->gopLength = gop_size;
  354. config->frameIntervalP = 1 + bf;
  355. h264_config->idrPeriod = gop_size;
  356. vui_params->videoSignalTypePresentFlag = 1;
  357. vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
  358. vui_params->colourDescriptionPresentFlag = 1;
  359. vui_params->colourMatrix = (voi->colorspace == VIDEO_CS_709) ? 1 : 5;
  360. vui_params->colourPrimaries = 1;
  361. vui_params->transferCharacteristics = 1;
  362. enc->bframes = bf > 0;
  363. /* lookahead */
  364. if (lookahead && nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_LOOKAHEAD)) {
  365. config->rcParams.lookaheadDepth = 8;
  366. config->rcParams.enableLookahead = 1;
  367. } else {
  368. lookahead = false;
  369. }
  370. /* psycho aq */
  371. if (nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ)) {
  372. config->rcParams.enableAQ = psycho_aq;
  373. config->rcParams.enableTemporalAQ = psycho_aq;
  374. }
  375. /* -------------------------- */
  376. /* rate control */
  377. enc->can_change_bitrate =
  378. nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE) &&
  379. !lookahead;
  380. config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ
  381. : NV_ENC_PARAMS_RC_VBR;
  382. if (astrcmpi(rc, "cqp") == 0 || astrcmpi(rc, "lossless") == 0) {
  383. if (astrcmpi(rc, "lossless") == 0)
  384. cqp = 0;
  385. config->rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
  386. config->rcParams.constQP.qpInterP = cqp;
  387. config->rcParams.constQP.qpInterB = cqp;
  388. config->rcParams.constQP.qpIntra = cqp;
  389. enc->can_change_bitrate = false;
  390. bitrate = 0;
  391. max_bitrate = 0;
  392. } else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
  393. h264_config->outputBufferingPeriodSEI = 1;
  394. config->rcParams.rateControlMode =
  395. twopass ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
  396. : NV_ENC_PARAMS_RC_CBR;
  397. }
  398. h264_config->outputPictureTimingSEI = 1;
  399. config->rcParams.averageBitRate = bitrate * 1000;
  400. config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
  401. /* -------------------------- */
  402. /* profile */
  403. if (astrcmpi(profile, "main") == 0) {
  404. config->profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
  405. } else if (astrcmpi(profile, "baseline") == 0) {
  406. config->profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
  407. } else {
  408. config->profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
  409. }
  410. /* -------------------------- */
  411. /* initialize */
  412. if (NV_FAILED(nv.nvEncInitializeEncoder(enc->session, params))) {
  413. return false;
  414. }
  415. enc->buf_count = config->frameIntervalP +
  416. config->rcParams.lookaheadDepth + EXTRA_BUFFERS;
  417. enc->output_delay = enc->buf_count - 1;
  418. info("settings:\n"
  419. "\trate_control: %s\n"
  420. "\tbitrate: %d\n"
  421. "\tcqp: %d\n"
  422. "\tkeyint: %d\n"
  423. "\tpreset: %s\n"
  424. "\tprofile: %s\n"
  425. "\twidth: %d\n"
  426. "\theight: %d\n"
  427. "\t2-pass: %s\n"
  428. "\tb-frames: %d\n"
  429. "\tlookahead: %s\n"
  430. "\tpsycho_aq: %s\n",
  431. rc, bitrate, cqp, gop_size, preset, profile, enc->cx, enc->cy,
  432. twopass ? "true" : "false", bf, 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,
  547. IDXGIKeyedMutex **km_out)
  548. {
  549. ID3D11Device *device = enc->device;
  550. IDXGIKeyedMutex *km;
  551. ID3D11Texture2D *input_tex;
  552. HRESULT hr;
  553. for (size_t i = 0; i < enc->input_textures.num; i++) {
  554. struct handle_tex *ht = &enc->input_textures.array[i];
  555. if (ht->handle == handle) {
  556. *km_out = ht->km;
  557. return ht->tex;
  558. }
  559. }
  560. hr = device->lpVtbl->OpenSharedResource(device,
  561. (HANDLE)(uintptr_t)handle,
  562. &IID_ID3D11Texture2D,
  563. &input_tex);
  564. if (FAILED(hr)) {
  565. error_hr("OpenSharedResource failed");
  566. return NULL;
  567. }
  568. hr = input_tex->lpVtbl->QueryInterface(input_tex, &IID_IDXGIKeyedMutex,
  569. &km);
  570. if (FAILED(hr)) {
  571. error_hr("QueryInterface(IDXGIKeyedMutex) failed");
  572. input_tex->lpVtbl->Release(input_tex);
  573. return NULL;
  574. }
  575. input_tex->lpVtbl->SetEvictionPriority(input_tex,
  576. DXGI_RESOURCE_PRIORITY_MAXIMUM);
  577. *km_out = km;
  578. struct handle_tex new_ht = {handle, input_tex, km};
  579. da_push_back(enc->input_textures, &new_ht);
  580. return input_tex;
  581. }
  582. static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
  583. {
  584. void *s = enc->session;
  585. da_resize(enc->packet_data, 0);
  586. if (!enc->buffers_queued)
  587. return true;
  588. if (!finalize && enc->buffers_queued < enc->output_delay)
  589. return true;
  590. size_t count = finalize ? enc->buffers_queued : 1;
  591. for (size_t i = 0; i < count; i++) {
  592. size_t cur_bs_idx = enc->cur_bitstream;
  593. struct nv_bitstream *bs = &enc->bitstreams.array[cur_bs_idx];
  594. struct nv_texture *nvtex = &enc->textures.array[cur_bs_idx];
  595. /* ---------------- */
  596. NV_ENC_LOCK_BITSTREAM lock = {NV_ENC_LOCK_BITSTREAM_VER};
  597. lock.outputBitstream = bs->ptr;
  598. lock.doNotWait = false;
  599. if (NV_FAILED(nv.nvEncLockBitstream(s, &lock))) {
  600. return false;
  601. }
  602. if (enc->first_packet) {
  603. uint8_t *new_packet;
  604. size_t size;
  605. enc->first_packet = false;
  606. obs_extract_avc_headers(lock.bitstreamBufferPtr,
  607. lock.bitstreamSizeInBytes,
  608. &new_packet, &size,
  609. &enc->header, &enc->header_size,
  610. &enc->sei, &enc->sei_size);
  611. da_copy_array(enc->packet_data, new_packet, size);
  612. bfree(new_packet);
  613. } else {
  614. da_copy_array(enc->packet_data, 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,
  641. bool *received_packet)
  642. {
  643. struct nvenc_data *enc = data;
  644. ID3D11Device *device = enc->device;
  645. ID3D11DeviceContext *context = enc->context;
  646. ID3D11Texture2D *input_tex;
  647. ID3D11Texture2D *output_tex;
  648. IDXGIKeyedMutex *km;
  649. struct nv_texture *nvtex;
  650. struct nv_bitstream *bs;
  651. NVENCSTATUS err;
  652. if (handle == GS_INVALID_HANDLE) {
  653. error("Encode failed: bad texture handle");
  654. *next_key = lock_key;
  655. return false;
  656. }
  657. bs = &enc->bitstreams.array[enc->next_bitstream];
  658. nvtex = &enc->textures.array[enc->next_bitstream];
  659. input_tex = get_tex_from_handle(enc, handle, &km);
  660. output_tex = nvtex->tex;
  661. if (!input_tex) {
  662. *next_key = lock_key;
  663. return false;
  664. }
  665. circlebuf_push_back(&enc->dts_list, &pts, sizeof(pts));
  666. /* ------------------------------------ */
  667. /* wait for output bitstream/tex */
  668. WaitForSingleObject(bs->event, INFINITE);
  669. /* ------------------------------------ */
  670. /* copy to output tex */
  671. km->lpVtbl->AcquireSync(km, lock_key, INFINITE);
  672. context->lpVtbl->CopyResource(context, (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 -= 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. };