jim-nvenc.c 25 KB

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