1 /* GStreamer NVENC plugin
2 * Copyright (C) 2015 Centricular Ltd
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstnvenc.h"
25 #include "gstnvh264enc.h"
26 #include "gstnvh265enc.h"
27 #include <gmodule.h>
28
29 #ifdef _WIN32
30 #ifdef _WIN64
31 #define NVENC_LIBRARY_NAME "nvEncodeAPI64.dll"
32 #else
33 #define NVENC_LIBRARY_NAME "nvEncodeAPI.dll"
34 #endif
35 #else
36 #define NVENC_LIBRARY_NAME "libnvidia-encode.so.1"
37 #endif
38
39 typedef NVENCSTATUS NVENCAPI
40 tNvEncodeAPICreateInstance (NV_ENCODE_API_FUNCTION_LIST * functionList);
41 tNvEncodeAPICreateInstance *nvEncodeAPICreateInstance;
42
43 GST_DEBUG_CATEGORY (gst_nvenc_debug);
44 #define GST_CAT_DEFAULT gst_nvenc_debug
45
46 static NV_ENCODE_API_FUNCTION_LIST nvenc_api;
47
48 NVENCSTATUS
NvEncOpenEncodeSessionEx(NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS * params,void ** encoder)49 NvEncOpenEncodeSessionEx (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS * params,
50 void **encoder)
51 {
52 g_assert (nvenc_api.nvEncOpenEncodeSessionEx != NULL);
53 return nvenc_api.nvEncOpenEncodeSessionEx (params, encoder);
54 }
55
56 NVENCSTATUS
NvEncDestroyEncoder(void * encoder)57 NvEncDestroyEncoder (void *encoder)
58 {
59 g_assert (nvenc_api.nvEncDestroyEncoder != NULL);
60 return nvenc_api.nvEncDestroyEncoder (encoder);
61 }
62
63 NVENCSTATUS
NvEncGetEncodeGUIDs(void * encoder,GUID * array,uint32_t array_size,uint32_t * count)64 NvEncGetEncodeGUIDs (void *encoder, GUID * array, uint32_t array_size,
65 uint32_t * count)
66 {
67 g_assert (nvenc_api.nvEncGetEncodeGUIDs != NULL);
68 return nvenc_api.nvEncGetEncodeGUIDs (encoder, array, array_size, count);
69 }
70
71 NVENCSTATUS
NvEncGetEncodeProfileGUIDCount(void * encoder,GUID encodeGUID,uint32_t * encodeProfileGUIDCount)72 NvEncGetEncodeProfileGUIDCount (void *encoder, GUID encodeGUID,
73 uint32_t * encodeProfileGUIDCount)
74 {
75 g_assert (nvenc_api.nvEncGetEncodeProfileGUIDCount != NULL);
76 return nvenc_api.nvEncGetEncodeProfileGUIDCount (encoder, encodeGUID,
77 encodeProfileGUIDCount);
78 }
79
80 NVENCSTATUS
NvEncGetEncodeProfileGUIDs(void * encoder,GUID encodeGUID,GUID * profileGUIDs,uint32_t guidArraySize,uint32_t * GUIDCount)81 NvEncGetEncodeProfileGUIDs (void *encoder, GUID encodeGUID,
82 GUID * profileGUIDs, uint32_t guidArraySize, uint32_t * GUIDCount)
83 {
84 g_assert (nvenc_api.nvEncGetEncodeProfileGUIDs != NULL);
85 return nvenc_api.nvEncGetEncodeProfileGUIDs (encoder, encodeGUID,
86 profileGUIDs, guidArraySize, GUIDCount);
87 }
88
89 NVENCSTATUS
NvEncGetInputFormats(void * encoder,GUID enc_guid,NV_ENC_BUFFER_FORMAT * array,uint32_t size,uint32_t * num)90 NvEncGetInputFormats (void *encoder, GUID enc_guid,
91 NV_ENC_BUFFER_FORMAT * array, uint32_t size, uint32_t * num)
92 {
93 g_assert (nvenc_api.nvEncGetInputFormats != NULL);
94 return nvenc_api.nvEncGetInputFormats (encoder, enc_guid, array, size, num);
95 }
96
97 NVENCSTATUS
NvEncGetEncodePresetCount(void * encoder,GUID encodeGUID,uint32_t * encodePresetGUIDCount)98 NvEncGetEncodePresetCount (void *encoder, GUID encodeGUID,
99 uint32_t * encodePresetGUIDCount)
100 {
101 g_assert (nvenc_api.nvEncGetEncodeProfileGUIDCount != NULL);
102 return nvenc_api.nvEncGetEncodePresetCount (encoder, encodeGUID,
103 encodePresetGUIDCount);
104 }
105
106 NVENCSTATUS
NvEncGetEncodePresetGUIDs(void * encoder,GUID encodeGUID,GUID * presetGUIDs,uint32_t guidArraySize,uint32_t * GUIDCount)107 NvEncGetEncodePresetGUIDs (void *encoder, GUID encodeGUID,
108 GUID * presetGUIDs, uint32_t guidArraySize, uint32_t * GUIDCount)
109 {
110 g_assert (nvenc_api.nvEncGetEncodeProfileGUIDs != NULL);
111 return nvenc_api.nvEncGetEncodePresetGUIDs (encoder, encodeGUID,
112 presetGUIDs, guidArraySize, GUIDCount);
113 }
114
115 NVENCSTATUS
NvEncGetEncodePresetConfig(void * encoder,GUID encodeGUID,GUID presetGUID,NV_ENC_PRESET_CONFIG * presetConfig)116 NvEncGetEncodePresetConfig (void *encoder, GUID encodeGUID,
117 GUID presetGUID, NV_ENC_PRESET_CONFIG * presetConfig)
118 {
119 g_assert (nvenc_api.nvEncGetEncodePresetConfig != NULL);
120 return nvenc_api.nvEncGetEncodePresetConfig (encoder, encodeGUID, presetGUID,
121 presetConfig);
122 }
123
124 NVENCSTATUS
NvEncGetEncodeCaps(void * encoder,GUID encodeGUID,NV_ENC_CAPS_PARAM * capsParam,int * capsVal)125 NvEncGetEncodeCaps (void *encoder, GUID encodeGUID,
126 NV_ENC_CAPS_PARAM * capsParam, int *capsVal)
127 {
128 g_assert (nvenc_api.nvEncGetEncodeCaps != NULL);
129 return nvenc_api.nvEncGetEncodeCaps (encoder, encodeGUID, capsParam, capsVal);
130 }
131
132 NVENCSTATUS
NvEncGetSequenceParams(void * encoder,NV_ENC_SEQUENCE_PARAM_PAYLOAD * sequenceParamPayload)133 NvEncGetSequenceParams (void *encoder,
134 NV_ENC_SEQUENCE_PARAM_PAYLOAD * sequenceParamPayload)
135 {
136 g_assert (nvenc_api.nvEncGetSequenceParams != NULL);
137 return nvenc_api.nvEncGetSequenceParams (encoder, sequenceParamPayload);
138 }
139
140 NVENCSTATUS
NvEncInitializeEncoder(void * encoder,NV_ENC_INITIALIZE_PARAMS * params)141 NvEncInitializeEncoder (void *encoder, NV_ENC_INITIALIZE_PARAMS * params)
142 {
143 g_assert (nvenc_api.nvEncInitializeEncoder != NULL);
144 return nvenc_api.nvEncInitializeEncoder (encoder, params);
145 }
146
147 NVENCSTATUS
NvEncReconfigureEncoder(void * encoder,NV_ENC_RECONFIGURE_PARAMS * params)148 NvEncReconfigureEncoder (void *encoder, NV_ENC_RECONFIGURE_PARAMS * params)
149 {
150 g_assert (nvenc_api.nvEncReconfigureEncoder != NULL);
151 return nvenc_api.nvEncReconfigureEncoder (encoder, params);
152 }
153
154 NVENCSTATUS
NvEncRegisterResource(void * encoder,NV_ENC_REGISTER_RESOURCE * params)155 NvEncRegisterResource (void *encoder, NV_ENC_REGISTER_RESOURCE * params)
156 {
157 g_assert (nvenc_api.nvEncRegisterResource != NULL);
158 return nvenc_api.nvEncRegisterResource (encoder, params);
159 }
160
161 NVENCSTATUS
NvEncUnregisterResource(void * encoder,NV_ENC_REGISTERED_PTR resource)162 NvEncUnregisterResource (void *encoder, NV_ENC_REGISTERED_PTR resource)
163 {
164 g_assert (nvenc_api.nvEncUnregisterResource != NULL);
165 return nvenc_api.nvEncUnregisterResource (encoder, resource);
166 }
167
168 NVENCSTATUS
NvEncMapInputResource(void * encoder,NV_ENC_MAP_INPUT_RESOURCE * params)169 NvEncMapInputResource (void *encoder, NV_ENC_MAP_INPUT_RESOURCE * params)
170 {
171 g_assert (nvenc_api.nvEncMapInputResource != NULL);
172 return nvenc_api.nvEncMapInputResource (encoder, params);
173 }
174
175 NVENCSTATUS
NvEncUnmapInputResource(void * encoder,NV_ENC_INPUT_PTR input_buffer)176 NvEncUnmapInputResource (void *encoder, NV_ENC_INPUT_PTR input_buffer)
177 {
178 g_assert (nvenc_api.nvEncUnmapInputResource != NULL);
179 return nvenc_api.nvEncUnmapInputResource (encoder, input_buffer);
180 }
181
182 NVENCSTATUS
NvEncCreateInputBuffer(void * encoder,NV_ENC_CREATE_INPUT_BUFFER * input_buf)183 NvEncCreateInputBuffer (void *encoder, NV_ENC_CREATE_INPUT_BUFFER * input_buf)
184 {
185 g_assert (nvenc_api.nvEncCreateInputBuffer != NULL);
186 return nvenc_api.nvEncCreateInputBuffer (encoder, input_buf);
187 }
188
189 NVENCSTATUS
NvEncLockInputBuffer(void * encoder,NV_ENC_LOCK_INPUT_BUFFER * input_buf)190 NvEncLockInputBuffer (void *encoder, NV_ENC_LOCK_INPUT_BUFFER * input_buf)
191 {
192 g_assert (nvenc_api.nvEncLockInputBuffer != NULL);
193 return nvenc_api.nvEncLockInputBuffer (encoder, input_buf);
194 }
195
196 NVENCSTATUS
NvEncUnlockInputBuffer(void * encoder,NV_ENC_INPUT_PTR input_buf)197 NvEncUnlockInputBuffer (void *encoder, NV_ENC_INPUT_PTR input_buf)
198 {
199 g_assert (nvenc_api.nvEncUnlockInputBuffer != NULL);
200 return nvenc_api.nvEncUnlockInputBuffer (encoder, input_buf);
201 }
202
203 NVENCSTATUS
NvEncDestroyInputBuffer(void * encoder,NV_ENC_INPUT_PTR input_buf)204 NvEncDestroyInputBuffer (void *encoder, NV_ENC_INPUT_PTR input_buf)
205 {
206 g_assert (nvenc_api.nvEncDestroyInputBuffer != NULL);
207 return nvenc_api.nvEncDestroyInputBuffer (encoder, input_buf);
208 }
209
210 NVENCSTATUS
NvEncCreateBitstreamBuffer(void * encoder,NV_ENC_CREATE_BITSTREAM_BUFFER * bb)211 NvEncCreateBitstreamBuffer (void *encoder, NV_ENC_CREATE_BITSTREAM_BUFFER * bb)
212 {
213 g_assert (nvenc_api.nvEncCreateBitstreamBuffer != NULL);
214 return nvenc_api.nvEncCreateBitstreamBuffer (encoder, bb);
215 }
216
217 NVENCSTATUS
NvEncLockBitstream(void * encoder,NV_ENC_LOCK_BITSTREAM * lock_bs)218 NvEncLockBitstream (void *encoder, NV_ENC_LOCK_BITSTREAM * lock_bs)
219 {
220 g_assert (nvenc_api.nvEncLockBitstream != NULL);
221 return nvenc_api.nvEncLockBitstream (encoder, lock_bs);
222 }
223
224 NVENCSTATUS
NvEncUnlockBitstream(void * encoder,NV_ENC_OUTPUT_PTR bb)225 NvEncUnlockBitstream (void *encoder, NV_ENC_OUTPUT_PTR bb)
226 {
227 g_assert (nvenc_api.nvEncUnlockBitstream != NULL);
228 return nvenc_api.nvEncUnlockBitstream (encoder, bb);
229 }
230
231 NVENCSTATUS
NvEncDestroyBitstreamBuffer(void * encoder,NV_ENC_OUTPUT_PTR bit_buf)232 NvEncDestroyBitstreamBuffer (void *encoder, NV_ENC_OUTPUT_PTR bit_buf)
233 {
234 g_assert (nvenc_api.nvEncDestroyBitstreamBuffer != NULL);
235 return nvenc_api.nvEncDestroyBitstreamBuffer (encoder, bit_buf);
236 }
237
238 NVENCSTATUS
NvEncEncodePicture(void * encoder,NV_ENC_PIC_PARAMS * pic_params)239 NvEncEncodePicture (void *encoder, NV_ENC_PIC_PARAMS * pic_params)
240 {
241 g_assert (nvenc_api.nvEncEncodePicture != NULL);
242 return nvenc_api.nvEncEncodePicture (encoder, pic_params);
243 }
244
245 gboolean
gst_nvenc_cmp_guid(GUID g1,GUID g2)246 gst_nvenc_cmp_guid (GUID g1, GUID g2)
247 {
248 return (g1.Data1 == g2.Data1 && g1.Data2 == g2.Data2 && g1.Data3 == g2.Data3
249 && g1.Data4[0] == g2.Data4[0] && g1.Data4[1] == g2.Data4[1]
250 && g1.Data4[2] == g2.Data4[2] && g1.Data4[3] == g2.Data4[3]
251 && g1.Data4[4] == g2.Data4[4] && g1.Data4[5] == g2.Data4[5]
252 && g1.Data4[6] == g2.Data4[6] && g1.Data4[7] == g2.Data4[7]);
253 }
254
255 NV_ENC_BUFFER_FORMAT
gst_nvenc_get_nv_buffer_format(GstVideoFormat fmt)256 gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt)
257 {
258 switch (fmt) {
259 case GST_VIDEO_FORMAT_NV12:
260 return NV_ENC_BUFFER_FORMAT_NV12_PL;
261 case GST_VIDEO_FORMAT_YV12:
262 return NV_ENC_BUFFER_FORMAT_YV12_PL;
263 case GST_VIDEO_FORMAT_I420:
264 return NV_ENC_BUFFER_FORMAT_IYUV_PL;
265 case GST_VIDEO_FORMAT_Y444:
266 return NV_ENC_BUFFER_FORMAT_YUV444_PL;
267 default:
268 break;
269 }
270 return NV_ENC_BUFFER_FORMAT_UNDEFINED;
271 }
272
273 CUcontext
gst_nvenc_create_cuda_context(guint device_id)274 gst_nvenc_create_cuda_context (guint device_id)
275 {
276 CUcontext cuda_ctx, old_ctx;
277 CUresult cres = CUDA_SUCCESS;
278 CUdevice cdev = 0, cuda_dev = -1;
279 int dev_count = 0;
280 char name[256];
281 int min = 0, maj = 0;
282 int i;
283
284 GST_INFO ("Initialising CUDA..");
285
286 cres = cuInit (0);
287
288 if (cres != CUDA_SUCCESS) {
289 GST_WARNING ("Failed to initialise CUDA, error code: 0x%08x", cres);
290 return NULL;
291 }
292
293 GST_INFO ("Initialised CUDA");
294
295 cres = cuDeviceGetCount (&dev_count);
296 if (cres != CUDA_SUCCESS || dev_count == 0) {
297 GST_WARNING ("No CUDA devices detected");
298 return NULL;
299 }
300
301 GST_INFO ("%d CUDA device(s) detected", dev_count);
302 for (i = 0; i < dev_count; ++i) {
303 if (cuDeviceGet (&cdev, i) == CUDA_SUCCESS
304 && cuDeviceGetName (name, sizeof (name), cdev) == CUDA_SUCCESS
305 && cuDeviceGetAttribute (&maj,
306 CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cdev) == CUDA_SUCCESS
307 && cuDeviceGetAttribute (&min,
308 CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
309 cdev) == CUDA_SUCCESS) {
310 GST_INFO ("GPU #%d supports NVENC: %s (%s) (Compute SM %d.%d)", i,
311 (((maj << 4) + min) >= 0x30) ? "yes" : "no", name, maj, min);
312 if (i == device_id) {
313 cuda_dev = cdev;
314 }
315 }
316 }
317
318 if (cuda_dev == -1) {
319 GST_WARNING ("Device with id %d does not exist or does not support NVENC",
320 device_id);
321 return NULL;
322 }
323
324 if (cuCtxCreate (&cuda_ctx, 0, cuda_dev) != CUDA_SUCCESS) {
325 GST_WARNING ("Failed to create CUDA context for cuda device %d", cuda_dev);
326 return NULL;
327 }
328
329 if (cuCtxPopCurrent (&old_ctx) != CUDA_SUCCESS) {
330 return NULL;
331 }
332
333 GST_INFO ("Created CUDA context %p", cuda_ctx);
334
335 return cuda_ctx;
336 }
337
338 gboolean
gst_nvenc_destroy_cuda_context(CUcontext ctx)339 gst_nvenc_destroy_cuda_context (CUcontext ctx)
340 {
341 GST_INFO ("Destroying CUDA context %p", ctx);
342 return (cuCtxDestroy (ctx) == CUDA_SUCCESS);
343 }
344
345 static gboolean
load_nvenc_library(void)346 load_nvenc_library (void)
347 {
348 GModule *module;
349
350 module = g_module_open (NVENC_LIBRARY_NAME, G_MODULE_BIND_LAZY);
351 if (module == NULL) {
352 GST_ERROR ("%s", g_module_error ());
353 return FALSE;
354 }
355
356 if (!g_module_symbol (module, "NvEncodeAPICreateInstance",
357 (gpointer *) & nvEncodeAPICreateInstance)) {
358 GST_ERROR ("%s", g_module_error ());
359 return FALSE;
360 }
361
362 return TRUE;
363 }
364
365 static gboolean
plugin_init(GstPlugin * plugin)366 plugin_init (GstPlugin * plugin)
367 {
368 GST_DEBUG_CATEGORY_INIT (gst_nvenc_debug, "nvenc", 0, "Nvidia NVENC encoder");
369
370 nvenc_api.version = NV_ENCODE_API_FUNCTION_LIST_VER;
371 if (!load_nvenc_library ())
372 return FALSE;
373
374 if (nvEncodeAPICreateInstance (&nvenc_api) != NV_ENC_SUCCESS) {
375 GST_ERROR ("Failed to get NVEncodeAPI function table!");
376 } else {
377 GST_INFO ("Created NVEncodeAPI instance, got function table");
378
379 gst_element_register (plugin, "nvh264enc", GST_RANK_PRIMARY * 2,
380 gst_nv_h264_enc_get_type ());
381 gst_element_register (plugin, "nvh265enc", GST_RANK_PRIMARY * 2,
382 gst_nv_h265_enc_get_type ());
383 }
384
385 return TRUE;
386 }
387
388 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
389 GST_VERSION_MINOR,
390 nvenc,
391 "GStreamer NVENC plugin",
392 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
393