diff options
Diffstat (limited to 'sys/nvenc/gstnvenc.c')
-rw-r--r-- | sys/nvenc/gstnvenc.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/sys/nvenc/gstnvenc.c b/sys/nvenc/gstnvenc.c new file mode 100644 index 000000000..6b0d5685c --- /dev/null +++ b/sys/nvenc/gstnvenc.c @@ -0,0 +1,328 @@ +/* GStreamer NVENC plugin + * Copyright (C) 2015 Centricular Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstnvenc.h" +#include "gstnvh264enc.h" + +GST_DEBUG_CATEGORY (gst_nvenc_debug); + +static NV_ENCODE_API_FUNCTION_LIST nvenc_api; + +NVENCSTATUS +NvEncOpenEncodeSessionEx (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS * params, + void **encoder) +{ + g_assert (nvenc_api.nvEncOpenEncodeSessionEx != NULL); + return nvenc_api.nvEncOpenEncodeSessionEx (params, encoder); +} + +NVENCSTATUS +NvEncDestroyEncoder (void *encoder) +{ + g_assert (nvenc_api.nvEncDestroyEncoder != NULL); + return nvenc_api.nvEncDestroyEncoder (encoder); +} + +NVENCSTATUS +NvEncGetEncodeGUIDs (void *encoder, GUID * array, uint32_t array_size, + uint32_t * count) +{ + g_assert (nvenc_api.nvEncGetEncodeGUIDs != NULL); + return nvenc_api.nvEncGetEncodeGUIDs (encoder, array, array_size, count); +} + +NVENCSTATUS +NvEncGetEncodeProfileGUIDCount (void *encoder, GUID encodeGUID, + uint32_t * encodeProfileGUIDCount) +{ + g_assert (nvenc_api.nvEncGetEncodeProfileGUIDCount != NULL); + return nvenc_api.nvEncGetEncodeProfileGUIDCount (encoder, encodeGUID, + encodeProfileGUIDCount); +} + +NVENCSTATUS +NvEncGetEncodeProfileGUIDs (void *encoder, GUID encodeGUID, + GUID * profileGUIDs, uint32_t guidArraySize, uint32_t * GUIDCount) +{ + g_assert (nvenc_api.nvEncGetEncodeProfileGUIDs != NULL); + return nvenc_api.nvEncGetEncodeProfileGUIDs (encoder, encodeGUID, + profileGUIDs, guidArraySize, GUIDCount); +} + +NVENCSTATUS +NvEncGetInputFormats (void *encoder, GUID enc_guid, + NV_ENC_BUFFER_FORMAT * array, uint32_t size, uint32_t * num) +{ + g_assert (nvenc_api.nvEncGetInputFormats != NULL); + return nvenc_api.nvEncGetInputFormats (encoder, enc_guid, array, size, num); +} + +NVENCSTATUS +NvEncGetEncodePresetConfig (void *encoder, GUID encodeGUID, + GUID presetGUID, NV_ENC_PRESET_CONFIG * presetConfig) +{ + g_assert (nvenc_api.nvEncGetEncodePresetConfig != NULL); + return nvenc_api.nvEncGetEncodePresetConfig (encoder, encodeGUID, presetGUID, + presetConfig); +} + +NVENCSTATUS +NvEncGetEncodeCaps (void *encoder, GUID encodeGUID, + NV_ENC_CAPS_PARAM * capsParam, int *capsVal) +{ + g_assert (nvenc_api.nvEncGetEncodeCaps != NULL); + return nvenc_api.nvEncGetEncodeCaps (encoder, encodeGUID, capsParam, capsVal); +} + +NVENCSTATUS +NvEncGetSequenceParams (void *encoder, + NV_ENC_SEQUENCE_PARAM_PAYLOAD * sequenceParamPayload) +{ + g_assert (nvenc_api.nvEncGetSequenceParams != NULL); + return nvenc_api.nvEncGetSequenceParams (encoder, sequenceParamPayload); +} + +NVENCSTATUS +NvEncInitializeEncoder (void *encoder, NV_ENC_INITIALIZE_PARAMS * params) +{ + g_assert (nvenc_api.nvEncInitializeEncoder != NULL); + return nvenc_api.nvEncInitializeEncoder (encoder, params); +} + +NVENCSTATUS +NvEncReconfigureEncoder (void *encoder, NV_ENC_RECONFIGURE_PARAMS * params) +{ + g_assert (nvenc_api.nvEncReconfigureEncoder != NULL); + return nvenc_api.nvEncReconfigureEncoder (encoder, params); +} + +NVENCSTATUS +NvEncRegisterResource (void *encoder, NV_ENC_REGISTER_RESOURCE * params) +{ + g_assert (nvenc_api.nvEncRegisterResource != NULL); + return nvenc_api.nvEncRegisterResource (encoder, params); +} + +NVENCSTATUS +NvEncUnregisterResource (void *encoder, NV_ENC_REGISTERED_PTR resource) +{ + g_assert (nvenc_api.nvEncUnregisterResource != NULL); + return nvenc_api.nvEncUnregisterResource (encoder, resource); +} + +NVENCSTATUS +NvEncMapInputResource (void *encoder, NV_ENC_MAP_INPUT_RESOURCE * params) +{ + g_assert (nvenc_api.nvEncMapInputResource != NULL); + return nvenc_api.nvEncMapInputResource (encoder, params); +} + +NVENCSTATUS +NvEncUnmapInputResource (void *encoder, NV_ENC_INPUT_PTR input_buffer) +{ + g_assert (nvenc_api.nvEncUnmapInputResource != NULL); + return nvenc_api.nvEncUnmapInputResource (encoder, input_buffer); +} + +NVENCSTATUS +NvEncCreateInputBuffer (void *encoder, NV_ENC_CREATE_INPUT_BUFFER * input_buf) +{ + g_assert (nvenc_api.nvEncCreateInputBuffer != NULL); + return nvenc_api.nvEncCreateInputBuffer (encoder, input_buf); +} + +NVENCSTATUS +NvEncLockInputBuffer (void *encoder, NV_ENC_LOCK_INPUT_BUFFER * input_buf) +{ + g_assert (nvenc_api.nvEncLockInputBuffer != NULL); + return nvenc_api.nvEncLockInputBuffer (encoder, input_buf); +} + +NVENCSTATUS +NvEncUnlockInputBuffer (void *encoder, NV_ENC_INPUT_PTR input_buf) +{ + g_assert (nvenc_api.nvEncUnlockInputBuffer != NULL); + return nvenc_api.nvEncUnlockInputBuffer (encoder, input_buf); +} + +NVENCSTATUS +NvEncDestroyInputBuffer (void *encoder, NV_ENC_INPUT_PTR input_buf) +{ + g_assert (nvenc_api.nvEncDestroyInputBuffer != NULL); + return nvenc_api.nvEncDestroyInputBuffer (encoder, input_buf); +} + +NVENCSTATUS +NvEncCreateBitstreamBuffer (void *encoder, NV_ENC_CREATE_BITSTREAM_BUFFER * bb) +{ + g_assert (nvenc_api.nvEncCreateBitstreamBuffer != NULL); + return nvenc_api.nvEncCreateBitstreamBuffer (encoder, bb); +} + +NVENCSTATUS +NvEncLockBitstream (void *encoder, NV_ENC_LOCK_BITSTREAM * lock_bs) +{ + g_assert (nvenc_api.nvEncLockBitstream != NULL); + return nvenc_api.nvEncLockBitstream (encoder, lock_bs); +} + +NVENCSTATUS +NvEncUnlockBitstream (void *encoder, NV_ENC_OUTPUT_PTR bb) +{ + g_assert (nvenc_api.nvEncUnlockBitstream != NULL); + return nvenc_api.nvEncUnlockBitstream (encoder, bb); +} + +NVENCSTATUS +NvEncDestroyBitstreamBuffer (void *encoder, NV_ENC_OUTPUT_PTR bit_buf) +{ + g_assert (nvenc_api.nvEncDestroyBitstreamBuffer != NULL); + return nvenc_api.nvEncDestroyBitstreamBuffer (encoder, bit_buf); +} + +NVENCSTATUS +NvEncEncodePicture (void *encoder, NV_ENC_PIC_PARAMS * pic_params) +{ + g_assert (nvenc_api.nvEncEncodePicture != NULL); + return nvenc_api.nvEncEncodePicture (encoder, pic_params); +} + +gboolean +gst_nvenc_cmp_guid (GUID g1, GUID g2) +{ + return (g1.Data1 == g2.Data1 && g1.Data2 == g2.Data2 && g1.Data3 == g2.Data3 + && g1.Data4[0] == g2.Data4[0] && g1.Data4[1] == g2.Data4[1] + && g1.Data4[2] == g2.Data4[2] && g1.Data4[3] == g2.Data4[3] + && g1.Data4[4] == g2.Data4[4] && g1.Data4[5] == g2.Data4[5] + && g1.Data4[6] == g2.Data4[6] && g1.Data4[7] == g2.Data4[7]); +} + +NV_ENC_BUFFER_FORMAT +gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt) +{ + switch (fmt) { + case GST_VIDEO_FORMAT_NV12: + return NV_ENC_BUFFER_FORMAT_NV12_PL; + case GST_VIDEO_FORMAT_YV12: + return NV_ENC_BUFFER_FORMAT_YV12_PL; + case GST_VIDEO_FORMAT_I420: + return NV_ENC_BUFFER_FORMAT_IYUV_PL; + case GST_VIDEO_FORMAT_Y444: + return NV_ENC_BUFFER_FORMAT_YUV444_PL; + default: + break; + } + return NV_ENC_BUFFER_FORMAT_UNDEFINED; +} + +CUcontext +gst_nvenc_create_cuda_context (guint device_id) +{ + CUcontext cuda_ctx, old_ctx; + CUresult cres = CUDA_SUCCESS; + CUdevice cdev = 0, cuda_dev = -1; + int dev_count = 0; + char name[256]; + int min = 0, maj = 0; + int i; + + GST_INFO ("Initialising CUDA.."); + + cres = cuInit (0); + + if (cres != CUDA_SUCCESS) { + GST_WARNING ("Failed to initialise CUDA, error code: 0x%08x", cres); + return NULL; + } + + GST_INFO ("Initialised CUDA"); + + cres = cuDeviceGetCount (&dev_count); + if (cres != CUDA_SUCCESS || dev_count == 0) { + GST_WARNING ("No CUDA devices detected"); + return NULL; + } + + GST_INFO ("%d CUDA device(s) detected", dev_count); + for (i = 0; i < dev_count; ++i) { + if (cuDeviceGet (&cdev, i) == CUDA_SUCCESS + && cuDeviceGetName (name, sizeof (name), cdev) == CUDA_SUCCESS + && cuDeviceComputeCapability (&maj, &min, cdev) == CUDA_SUCCESS) { + GST_INFO ("GPU #%d supports NVENC: %s (%s) (Compute SM %d.%d)", + i, (((maj << 4) + min) >= 0x30) ? "yes" : "no", name, maj, min); + if (i == device_id) { + cuda_dev = cdev; + } + } + } + + if (cuda_dev == -1) { + GST_WARNING ("Device with id %d does not exist or does not support NVENC", + device_id); + return NULL; + } + + if (cuCtxCreate (&cuda_ctx, 0, cuda_dev) != CUDA_SUCCESS) { + GST_WARNING ("Failed to create CUDA context for cuda device %d", cuda_dev); + return NULL; + } + + if (cuCtxPopCurrent (&old_ctx) != CUDA_SUCCESS) { + return NULL; + } + + GST_INFO ("Created CUDA context %p", cuda_ctx); + + return cuda_ctx; +} + +gboolean +gst_nvenc_destroy_cuda_context (CUcontext ctx) +{ + GST_INFO ("Destroying CUDA context %p", ctx); + return (cuCtxDestroy (ctx) == CUDA_SUCCESS); +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_nvenc_debug, "nvenc", 0, "Nvidia NVENC encoder"); + + nvenc_api.version = NV_ENCODE_API_FUNCTION_LIST_VER; + if (NvEncodeAPICreateInstance (&nvenc_api) != NV_ENC_SUCCESS) { + GST_ERROR ("Failed to get NVEncodeAPI function table!"); + } else { + GST_INFO ("Created NVEncodeAPI instance, got function table"); + + gst_element_register (plugin, "nvh264enc", GST_RANK_PRIMARY * 2, + gst_nv_h264_enc_get_type ()); + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + nvenc, + "GStreamer NVENC plugin", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) |