So applications and elements implemented outside GStreamer can reuse our infrastructure Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1472>
		
			
				
	
	
		
			1152 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1152 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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"
 | |
| #include "gstnvh265enc.h"
 | |
| #include <gst/cuda/gstcudautils.h>
 | |
| #include <gst/cuda/gstcudabufferpool.h>
 | |
| 
 | |
| #include <gmodule.h>
 | |
| 
 | |
| #if HAVE_NVCODEC_GST_GL
 | |
| #include <gst/gl/gl.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef _WIN32
 | |
| #ifdef _WIN64
 | |
| #define NVENC_LIBRARY_NAME "nvEncodeAPI64.dll"
 | |
| #else
 | |
| #define NVENC_LIBRARY_NAME "nvEncodeAPI.dll"
 | |
| #endif
 | |
| #else
 | |
| #define NVENC_LIBRARY_NAME "libnvidia-encode.so.1"
 | |
| #endif
 | |
| 
 | |
| /* For backward compatibility */
 | |
| #define GST_NVENC_MIN_API_MAJOR_VERSION 8
 | |
| #define GST_NVENC_MIN_API_MINOR_VERSION 1
 | |
| 
 | |
| #define GST_NVENCAPI_VERSION(major,minor) ((major) | ((minor) << 24))
 | |
| #define GST_NVENCAPI_STRUCT_VERSION(ver,api_ver) ((uint32_t)(api_ver) | ((ver)<<16) | (0x7 << 28))
 | |
| 
 | |
| static guint32 gst_nvenc_api_version = NVENCAPI_VERSION;
 | |
| 
 | |
| typedef NVENCSTATUS NVENCAPI
 | |
| tNvEncodeAPICreateInstance (NV_ENCODE_API_FUNCTION_LIST * functionList);
 | |
| tNvEncodeAPICreateInstance *nvEncodeAPICreateInstance;
 | |
| 
 | |
| typedef NVENCSTATUS NVENCAPI
 | |
| tNvEncodeAPIGetMaxSupportedVersion (uint32_t * version);
 | |
| tNvEncodeAPIGetMaxSupportedVersion *nvEncodeAPIGetMaxSupportedVersion;
 | |
| 
 | |
| GST_DEBUG_CATEGORY_EXTERN (gst_nvenc_debug);
 | |
| #define GST_CAT_DEFAULT gst_nvenc_debug
 | |
| 
 | |
| static NV_ENCODE_API_FUNCTION_LIST nvenc_api;
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncOpenEncodeSessionEx (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS * params,
 | |
|     void **encoder)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncOpenEncodeSessionEx != NULL);
 | |
|   return nvenc_api.nvEncOpenEncodeSessionEx (params, encoder);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncDestroyEncoder (void *encoder)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncDestroyEncoder != NULL);
 | |
|   return nvenc_api.nvEncDestroyEncoder (encoder);
 | |
| }
 | |
| 
 | |
| const char *NVENCAPI
 | |
| NvEncGetLastErrorString (void *encoder)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncGetLastErrorString != NULL);
 | |
|   return nvenc_api.nvEncGetLastErrorString (encoder);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| 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 NVENCAPI
 | |
| NvEncGetEncodeProfileGUIDCount (void *encoder, GUID encodeGUID,
 | |
|     uint32_t * encodeProfileGUIDCount)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncGetEncodeProfileGUIDCount != NULL);
 | |
|   return nvenc_api.nvEncGetEncodeProfileGUIDCount (encoder, encodeGUID,
 | |
|       encodeProfileGUIDCount);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| 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 NVENCAPI
 | |
| 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 NVENCAPI
 | |
| NvEncGetEncodePresetCount (void *encoder, GUID encodeGUID,
 | |
|     uint32_t * encodePresetGUIDCount)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncGetEncodeProfileGUIDCount != NULL);
 | |
|   return nvenc_api.nvEncGetEncodePresetCount (encoder, encodeGUID,
 | |
|       encodePresetGUIDCount);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncGetEncodePresetGUIDs (void *encoder, GUID encodeGUID,
 | |
|     GUID * presetGUIDs, uint32_t guidArraySize, uint32_t * GUIDCount)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncGetEncodeProfileGUIDs != NULL);
 | |
|   return nvenc_api.nvEncGetEncodePresetGUIDs (encoder, encodeGUID,
 | |
|       presetGUIDs, guidArraySize, GUIDCount);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| 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 NVENCAPI
 | |
| 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 NVENCAPI
 | |
| NvEncGetSequenceParams (void *encoder,
 | |
|     NV_ENC_SEQUENCE_PARAM_PAYLOAD * sequenceParamPayload)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncGetSequenceParams != NULL);
 | |
|   return nvenc_api.nvEncGetSequenceParams (encoder, sequenceParamPayload);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncInitializeEncoder (void *encoder, NV_ENC_INITIALIZE_PARAMS * params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncInitializeEncoder != NULL);
 | |
|   return nvenc_api.nvEncInitializeEncoder (encoder, params);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncReconfigureEncoder (void *encoder, NV_ENC_RECONFIGURE_PARAMS * params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncReconfigureEncoder != NULL);
 | |
|   return nvenc_api.nvEncReconfigureEncoder (encoder, params);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncRegisterResource (void *encoder, NV_ENC_REGISTER_RESOURCE * params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncRegisterResource != NULL);
 | |
|   return nvenc_api.nvEncRegisterResource (encoder, params);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncUnregisterResource (void *encoder, NV_ENC_REGISTERED_PTR resource)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncUnregisterResource != NULL);
 | |
|   return nvenc_api.nvEncUnregisterResource (encoder, resource);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncMapInputResource (void *encoder, NV_ENC_MAP_INPUT_RESOURCE * params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncMapInputResource != NULL);
 | |
|   return nvenc_api.nvEncMapInputResource (encoder, params);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncUnmapInputResource (void *encoder, NV_ENC_INPUT_PTR input_buffer)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncUnmapInputResource != NULL);
 | |
|   return nvenc_api.nvEncUnmapInputResource (encoder, input_buffer);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncCreateInputBuffer (void *encoder, NV_ENC_CREATE_INPUT_BUFFER * input_buf)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncCreateInputBuffer != NULL);
 | |
|   return nvenc_api.nvEncCreateInputBuffer (encoder, input_buf);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncLockInputBuffer (void *encoder, NV_ENC_LOCK_INPUT_BUFFER * input_buf)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncLockInputBuffer != NULL);
 | |
|   return nvenc_api.nvEncLockInputBuffer (encoder, input_buf);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncUnlockInputBuffer (void *encoder, NV_ENC_INPUT_PTR input_buf)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncUnlockInputBuffer != NULL);
 | |
|   return nvenc_api.nvEncUnlockInputBuffer (encoder, input_buf);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncDestroyInputBuffer (void *encoder, NV_ENC_INPUT_PTR input_buf)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncDestroyInputBuffer != NULL);
 | |
|   return nvenc_api.nvEncDestroyInputBuffer (encoder, input_buf);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncCreateBitstreamBuffer (void *encoder, NV_ENC_CREATE_BITSTREAM_BUFFER * bb)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncCreateBitstreamBuffer != NULL);
 | |
|   return nvenc_api.nvEncCreateBitstreamBuffer (encoder, bb);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncLockBitstream (void *encoder, NV_ENC_LOCK_BITSTREAM * lock_bs)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncLockBitstream != NULL);
 | |
|   return nvenc_api.nvEncLockBitstream (encoder, lock_bs);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncUnlockBitstream (void *encoder, NV_ENC_OUTPUT_PTR bb)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncUnlockBitstream != NULL);
 | |
|   return nvenc_api.nvEncUnlockBitstream (encoder, bb);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncDestroyBitstreamBuffer (void *encoder, NV_ENC_OUTPUT_PTR bit_buf)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncDestroyBitstreamBuffer != NULL);
 | |
|   return nvenc_api.nvEncDestroyBitstreamBuffer (encoder, bit_buf);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncEncodePicture (void *encoder, NV_ENC_PIC_PARAMS * pic_params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncEncodePicture != NULL);
 | |
|   return nvenc_api.nvEncEncodePicture (encoder, pic_params);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncRegisterAsyncEvent (void *encoder, NV_ENC_EVENT_PARAMS * event_params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncRegisterAsyncEvent != NULL);
 | |
|   return nvenc_api.nvEncRegisterAsyncEvent (encoder, event_params);
 | |
| }
 | |
| 
 | |
| NVENCSTATUS NVENCAPI
 | |
| NvEncUnregisterAsyncEvent (void *encoder, NV_ENC_EVENT_PARAMS * event_params)
 | |
| {
 | |
|   g_assert (nvenc_api.nvEncUnregisterAsyncEvent != NULL);
 | |
|   return nvenc_api.nvEncUnregisterAsyncEvent (encoder, event_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;
 | |
|     case GST_VIDEO_FORMAT_P010_10LE:
 | |
|     case GST_VIDEO_FORMAT_P010_10BE:
 | |
|       return NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
 | |
|     case GST_VIDEO_FORMAT_BGRA:
 | |
|       return NV_ENC_BUFFER_FORMAT_ARGB;
 | |
|     case GST_VIDEO_FORMAT_RGBA:
 | |
|       return NV_ENC_BUFFER_FORMAT_ABGR;
 | |
|     case GST_VIDEO_FORMAT_BGR10A2_LE:
 | |
|       return NV_ENC_BUFFER_FORMAT_ARGB10;
 | |
|     case GST_VIDEO_FORMAT_RGB10A2_LE:
 | |
|       return NV_ENC_BUFFER_FORMAT_ABGR10;
 | |
|     case GST_VIDEO_FORMAT_Y444_16LE:
 | |
|     case GST_VIDEO_FORMAT_Y444_16BE:
 | |
|       return NV_ENC_BUFFER_FORMAT_YUV444_10BIT;
 | |
|     case GST_VIDEO_FORMAT_VUYA:
 | |
|       return NV_ENC_BUFFER_FORMAT_AYUV;
 | |
|     default:
 | |
|       break;
 | |
|   }
 | |
|   return NV_ENC_BUFFER_FORMAT_UNDEFINED;
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   GstVideoFormat gst_format;
 | |
|   NV_ENC_BUFFER_FORMAT nv_format;
 | |
|   gboolean is_10bit;
 | |
| 
 | |
|   gboolean supported;
 | |
| } GstNvEncFormat;
 | |
| 
 | |
| gboolean
 | |
| gst_nvenc_get_supported_input_formats (gpointer encoder, GUID codec_id,
 | |
|     GValue ** formats)
 | |
| {
 | |
|   guint32 i, count = 0;
 | |
|   NV_ENC_BUFFER_FORMAT format_list[64];
 | |
|   GValue val = G_VALUE_INIT;
 | |
|   GValue *ret = NULL;
 | |
|   NV_ENC_CAPS_PARAM param = { 0, };
 | |
|   gint support_yuv444 = 0;
 | |
|   gint support_10bit = 0;
 | |
|   guint num_format = 0;
 | |
|   GstNvEncFormat format_map[] = {
 | |
|     {GST_VIDEO_FORMAT_NV12, NV_ENC_BUFFER_FORMAT_NV12, FALSE, FALSE},
 | |
|     {GST_VIDEO_FORMAT_YV12, NV_ENC_BUFFER_FORMAT_YV12, FALSE, FALSE},
 | |
|     {GST_VIDEO_FORMAT_I420, NV_ENC_BUFFER_FORMAT_IYUV, FALSE, FALSE},
 | |
|     {GST_VIDEO_FORMAT_BGRA, NV_ENC_BUFFER_FORMAT_ARGB, FALSE, FALSE},
 | |
|     {GST_VIDEO_FORMAT_RGBA, NV_ENC_BUFFER_FORMAT_ABGR, FALSE, FALSE},
 | |
|     {GST_VIDEO_FORMAT_Y444, NV_ENC_BUFFER_FORMAT_YUV444, FALSE, FALSE},
 | |
|     {GST_VIDEO_FORMAT_VUYA, NV_ENC_BUFFER_FORMAT_AYUV, FALSE, FALSE},
 | |
| #if G_BYTE_ORDER == G_LITTLE_ENDIAN
 | |
|     {GST_VIDEO_FORMAT_P010_10LE, NV_ENC_BUFFER_FORMAT_YUV420_10BIT, TRUE,
 | |
|         FALSE},
 | |
|     {GST_VIDEO_FORMAT_BGR10A2_LE, NV_ENC_BUFFER_FORMAT_ARGB10, TRUE,
 | |
|         FALSE},
 | |
|     {GST_VIDEO_FORMAT_RGB10A2_LE, NV_ENC_BUFFER_FORMAT_ABGR10, TRUE,
 | |
|         FALSE},
 | |
|     {GST_VIDEO_FORMAT_Y444_16LE, NV_ENC_BUFFER_FORMAT_YUV444_10BIT, TRUE,
 | |
|         FALSE},
 | |
| #else
 | |
|     {GST_VIDEO_FORMAT_P010_10BE, NV_ENC_BUFFER_FORMAT_YUV420_10BIT, TRUE,
 | |
|         FALSE},
 | |
|     {GST_VIDEO_FORMAT_Y444_16BE, NV_ENC_BUFFER_FORMAT_YUV444_10BIT, TRUE,
 | |
|         FALSE},
 | |
|     /* FIXME: No 10bits big-endian ARGB10 format is defined */
 | |
| #endif
 | |
|   };
 | |
| 
 | |
|   param.version = gst_nvenc_get_caps_param_version ();
 | |
|   param.capsToQuery = NV_ENC_CAPS_SUPPORT_YUV444_ENCODE;
 | |
|   if (NvEncGetEncodeCaps (encoder,
 | |
|           codec_id, ¶m, &support_yuv444) != NV_ENC_SUCCESS) {
 | |
|     support_yuv444 = 0;
 | |
|   }
 | |
| 
 | |
|   param.capsToQuery = NV_ENC_CAPS_SUPPORT_10BIT_ENCODE;
 | |
|   if (NvEncGetEncodeCaps (encoder,
 | |
|           codec_id, ¶m, &support_10bit) != NV_ENC_SUCCESS) {
 | |
|     support_10bit = 0;
 | |
|   }
 | |
| 
 | |
|   if (NvEncGetInputFormats (encoder,
 | |
|           codec_id, format_list, G_N_ELEMENTS (format_list),
 | |
|           &count) != NV_ENC_SUCCESS || count == 0) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   for (i = 0; i < count; i++) {
 | |
|     GST_INFO ("input format: 0x%08x", format_list[i]);
 | |
|     switch (format_list[i]) {
 | |
|       case NV_ENC_BUFFER_FORMAT_NV12:
 | |
|       case NV_ENC_BUFFER_FORMAT_YV12:
 | |
|       case NV_ENC_BUFFER_FORMAT_IYUV:
 | |
|       case NV_ENC_BUFFER_FORMAT_ARGB:
 | |
|       case NV_ENC_BUFFER_FORMAT_ABGR:
 | |
|         if (!format_map[i].supported) {
 | |
|           format_map[i].supported = TRUE;
 | |
|           num_format++;
 | |
|         }
 | |
|         break;
 | |
|       case NV_ENC_BUFFER_FORMAT_YUV444:
 | |
|       case NV_ENC_BUFFER_FORMAT_AYUV:
 | |
|         if (support_yuv444 && !format_map[i].supported) {
 | |
|           format_map[i].supported = TRUE;
 | |
|           num_format++;
 | |
|         }
 | |
|         break;
 | |
|       case NV_ENC_BUFFER_FORMAT_YUV420_10BIT:
 | |
|         if (support_10bit && !format_map[i].supported) {
 | |
|           format_map[i].supported = TRUE;
 | |
|           num_format++;
 | |
|         }
 | |
|         break;
 | |
|       case NV_ENC_BUFFER_FORMAT_YUV444_10BIT:
 | |
|         if (support_yuv444 && support_10bit && !format_map[i].supported) {
 | |
|           format_map[i].supported = TRUE;
 | |
|           num_format++;
 | |
|         }
 | |
|         break;
 | |
| #if G_BYTE_ORDER == G_LITTLE_ENDIAN
 | |
|       case NV_ENC_BUFFER_FORMAT_ARGB10:
 | |
|       case NV_ENC_BUFFER_FORMAT_ABGR10:
 | |
|         if (support_10bit && !format_map[i].supported) {
 | |
|           format_map[i].supported = TRUE;
 | |
|           num_format++;
 | |
|         }
 | |
|         break;
 | |
| #endif
 | |
|       default:
 | |
|         GST_FIXME ("unmapped input format: 0x%08x", format_list[i]);
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (num_format == 0)
 | |
|     return FALSE;
 | |
| 
 | |
|   /* process a second time so we can add formats in the order we want */
 | |
|   g_value_init (&val, G_TYPE_STRING);
 | |
|   ret = g_new0 (GValue, 1);
 | |
|   g_value_init (ret, GST_TYPE_LIST);
 | |
| 
 | |
|   for (i = 0; i < G_N_ELEMENTS (format_map); i++) {
 | |
|     if (!format_map[i].supported)
 | |
|       continue;
 | |
| 
 | |
|     g_value_set_static_string (&val,
 | |
|         gst_video_format_to_string (format_map[i].gst_format));
 | |
| 
 | |
|     gst_value_list_append_value (ret, &val);
 | |
|   }
 | |
| 
 | |
|   g_value_unset (&val);
 | |
| 
 | |
|   *formats = ret;
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| GValue *
 | |
| gst_nvenc_get_interlace_modes (gpointer enc, GUID codec_id)
 | |
| {
 | |
|   NV_ENC_CAPS_PARAM caps_param = { 0, };
 | |
|   GValue *list;
 | |
|   GValue val = G_VALUE_INIT;
 | |
|   gint interlace_modes = 0;
 | |
| 
 | |
|   caps_param.version = gst_nvenc_get_caps_param_version ();
 | |
|   caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_FIELD_ENCODING;
 | |
| 
 | |
|   if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
 | |
|           &interlace_modes) != NV_ENC_SUCCESS)
 | |
|     interlace_modes = 0;
 | |
| 
 | |
|   list = g_new0 (GValue, 1);
 | |
| 
 | |
|   g_value_init (list, GST_TYPE_LIST);
 | |
|   g_value_init (&val, G_TYPE_STRING);
 | |
| 
 | |
|   g_value_set_static_string (&val, "progressive");
 | |
|   gst_value_list_append_value (list, &val);
 | |
| 
 | |
|   if (interlace_modes == 0)
 | |
|     return list;
 | |
| 
 | |
|   if (interlace_modes >= 1) {
 | |
|     g_value_set_static_string (&val, "interleaved");
 | |
|     gst_value_list_append_value (list, &val);
 | |
|     g_value_set_static_string (&val, "mixed");
 | |
|     gst_value_list_append_value (list, &val);
 | |
|     g_value_unset (&val);
 | |
|   }
 | |
|   /* TODO: figure out what nvenc frame based interlacing means in gst terms */
 | |
| 
 | |
|   return list;
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   const gchar *gst_profile;
 | |
|   const GUID nv_profile;
 | |
|   const GUID codec_id;
 | |
|   const gboolean need_yuv444;
 | |
|   const gboolean need_10bit;
 | |
| 
 | |
|   gboolean supported;
 | |
| } GstNvEncCodecProfile;
 | |
| 
 | |
| GValue *
 | |
| gst_nvenc_get_supported_codec_profiles (gpointer enc, GUID codec_id)
 | |
| {
 | |
|   NVENCSTATUS nv_ret;
 | |
|   GUID profile_guids[64];
 | |
|   GValue *ret;
 | |
|   GValue val = G_VALUE_INIT;
 | |
|   guint i, j, n, n_profiles;
 | |
|   NV_ENC_CAPS_PARAM param = { 0, };
 | |
|   gint support_yuv444 = 0;
 | |
|   gint support_10bit = 0;
 | |
|   GstNvEncCodecProfile profiles[] = {
 | |
|     /* avc profiles */
 | |
|     {"main", NV_ENC_H264_PROFILE_MAIN_GUID, NV_ENC_CODEC_H264_GUID, FALSE,
 | |
|         FALSE, FALSE},
 | |
|     {"high", NV_ENC_H264_PROFILE_HIGH_GUID, NV_ENC_CODEC_H264_GUID, FALSE,
 | |
|         FALSE, FALSE},
 | |
|     {"high-4:4:4", NV_ENC_H264_PROFILE_HIGH_444_GUID, NV_ENC_CODEC_H264_GUID,
 | |
|         TRUE, FALSE, FALSE},
 | |
|     /* put baseline to last since it does not support bframe */
 | |
|     {"baseline", NV_ENC_H264_PROFILE_BASELINE_GUID, NV_ENC_CODEC_H264_GUID,
 | |
|         FALSE, FALSE, FALSE},
 | |
|     {"constrained-baseline", NV_ENC_H264_PROFILE_BASELINE_GUID,
 | |
|           NV_ENC_CODEC_H264_GUID,
 | |
|         FALSE, FALSE, FALSE},
 | |
|     /* hevc profiles */
 | |
|     {"main", NV_ENC_HEVC_PROFILE_MAIN_GUID, NV_ENC_CODEC_HEVC_GUID, FALSE,
 | |
|         FALSE, FALSE},
 | |
|     {"main-10", NV_ENC_HEVC_PROFILE_MAIN10_GUID, NV_ENC_CODEC_HEVC_GUID, FALSE,
 | |
|         TRUE, FALSE},
 | |
|     {"main-444", NV_ENC_HEVC_PROFILE_FREXT_GUID, NV_ENC_CODEC_HEVC_GUID, TRUE,
 | |
|         FALSE, FALSE},
 | |
| #if 0
 | |
|     /* FIXME: seems to unsupported format */
 | |
|     {"main-444-10", NV_ENC_HEVC_PROFILE_FREXT_GUID, FALSE}
 | |
| #endif
 | |
|   };
 | |
| 
 | |
|   param.version = gst_nvenc_get_caps_param_version ();
 | |
|   param.capsToQuery = NV_ENC_CAPS_SUPPORT_YUV444_ENCODE;
 | |
|   if (NvEncGetEncodeCaps (enc,
 | |
|           codec_id, ¶m, &support_yuv444) != NV_ENC_SUCCESS) {
 | |
|     support_yuv444 = 0;
 | |
|   }
 | |
| 
 | |
|   param.capsToQuery = NV_ENC_CAPS_SUPPORT_10BIT_ENCODE;
 | |
|   if (NvEncGetEncodeCaps (enc,
 | |
|           codec_id, ¶m, &support_10bit) != NV_ENC_SUCCESS) {
 | |
|     support_10bit = 0;
 | |
|   }
 | |
| 
 | |
|   nv_ret = NvEncGetEncodeProfileGUIDCount (enc, codec_id, &n);
 | |
| 
 | |
|   if (nv_ret != NV_ENC_SUCCESS)
 | |
|     return NULL;
 | |
| 
 | |
|   nv_ret = NvEncGetEncodeProfileGUIDs (enc,
 | |
|       codec_id, profile_guids, G_N_ELEMENTS (profile_guids), &n);
 | |
| 
 | |
|   if (nv_ret != NV_ENC_SUCCESS)
 | |
|     return NULL;
 | |
| 
 | |
|   n_profiles = 0;
 | |
| 
 | |
|   for (i = 0; i < n; i++) {
 | |
|     for (j = 0; j < G_N_ELEMENTS (profiles); j++) {
 | |
|       if (profiles[j].supported == FALSE &&
 | |
|           gst_nvenc_cmp_guid (profile_guids[i], profiles[j].nv_profile) &&
 | |
|           gst_nvenc_cmp_guid (codec_id, profiles[j].codec_id)) {
 | |
|         if (profiles[j].need_yuv444 && !support_yuv444)
 | |
|           continue;
 | |
| 
 | |
|         if (profiles[j].need_10bit && !support_10bit)
 | |
|           continue;
 | |
| 
 | |
|         profiles[j].supported = TRUE;
 | |
|         n_profiles++;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (n_profiles == 0)
 | |
|     return NULL;
 | |
| 
 | |
|   ret = g_new0 (GValue, 1);
 | |
| 
 | |
|   g_value_init (ret, GST_TYPE_LIST);
 | |
|   g_value_init (&val, G_TYPE_STRING);
 | |
| 
 | |
|   for (i = 0; i < G_N_ELEMENTS (profiles); i++) {
 | |
|     if (!profiles[i].supported)
 | |
|       continue;
 | |
| 
 | |
|     g_value_set_static_string (&val, profiles[i].gst_profile);
 | |
|     gst_value_list_append_value (ret, &val);
 | |
|   }
 | |
| 
 | |
|   g_value_unset (&val);
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| #define DEBUG_DEVICE_CAPS(d,c,caps,s) \
 | |
|   GST_DEBUG ("[device-%d %s] %s: %s", \
 | |
|       d, c, caps, s ? "supported" : "not supported");
 | |
| 
 | |
| #define ERROR_DETAILS "codec %s, device %i, error code %i"
 | |
| 
 | |
| static void
 | |
| gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec,
 | |
|     guint rank, gint device_index, CUcontext cuda_ctx)
 | |
| {
 | |
|   {
 | |
|     GValue *formats = NULL;
 | |
|     GValue *profiles;
 | |
|     GValue *interlace_modes;
 | |
|     gpointer enc;
 | |
|     NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0, };
 | |
|     NV_ENC_CAPS_PARAM caps_param = { 0, };
 | |
|     GUID guids[16];
 | |
|     guint32 count;
 | |
|     gint max_width = 0;
 | |
|     gint max_height = 0;
 | |
|     gint min_width = 16;
 | |
|     gint min_height = 16;
 | |
|     GstCaps *sink_templ = NULL;
 | |
|     GstCaps *src_templ = NULL;
 | |
|     gchar *name;
 | |
|     gint j;
 | |
|     GstNvEncDeviceCaps device_caps = { 0, };
 | |
|     NVENCSTATUS status;
 | |
|     CUresult cu_res;
 | |
| 
 | |
|     params.version = gst_nvenc_get_open_encode_session_ex_params_version ();
 | |
|     params.apiVersion = gst_nvenc_get_api_version ();
 | |
|     params.device = cuda_ctx;
 | |
|     params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
 | |
| 
 | |
|     if ((cu_res = CuCtxPushCurrent (cuda_ctx)) != CUDA_SUCCESS) {
 | |
|       GST_ERROR ("CuCtxPushCurrent failed: " ERROR_DETAILS, codec,
 | |
|           device_index, cu_res);
 | |
|       goto done;
 | |
|     }
 | |
| 
 | |
|     if ((status = NvEncOpenEncodeSessionEx (¶ms, &enc)) != NV_ENC_SUCCESS) {
 | |
|       CuCtxPopCurrent (NULL);
 | |
|       GST_ERROR ("NvEncOpenEncodeSessionEx failed: " ERROR_DETAILS, codec,
 | |
|           device_index, status);
 | |
|       goto done;
 | |
|     }
 | |
| 
 | |
|     if ((status = NvEncGetEncodeGUIDs (enc, guids, G_N_ELEMENTS (guids),
 | |
|                 &count)) != NV_ENC_SUCCESS) {
 | |
|       GST_ERROR ("NvEncGetEncodeGUIDs failed: " ERROR_DETAILS, codec,
 | |
|           device_index, status);
 | |
|       goto enc_free;
 | |
|     }
 | |
| 
 | |
|     for (j = 0; j < count; j++) {
 | |
|       if (gst_nvenc_cmp_guid (guids[j], codec_id))
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     if (j == count)
 | |
|       goto enc_free;
 | |
| 
 | |
|     if (!gst_nvenc_get_supported_input_formats (enc, codec_id, &formats))
 | |
|       goto enc_free;
 | |
| 
 | |
|     profiles = gst_nvenc_get_supported_codec_profiles (enc, codec_id);
 | |
|     if (!profiles)
 | |
|       goto free_format;
 | |
| 
 | |
|     caps_param.version = gst_nvenc_get_caps_param_version ();
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_WIDTH_MAX;
 | |
|     if ((status = NvEncGetEncodeCaps (enc,
 | |
|                 codec_id, &caps_param, &max_width)) != NV_ENC_SUCCESS) {
 | |
|       max_width = 4096;
 | |
|       GST_WARNING ("could not query max width, setting as %i: "
 | |
|           ERROR_DETAILS, max_width, codec, device_index, status);
 | |
|     } else if (max_width < 4096) {
 | |
|       GST_WARNING ("max width %d is less than expected value", max_width);
 | |
|       max_width = 4096;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_HEIGHT_MAX;
 | |
|     if ((status = NvEncGetEncodeCaps (enc,
 | |
|                 codec_id, &caps_param, &max_height)) != NV_ENC_SUCCESS) {
 | |
|       GST_WARNING ("could not query max height, setting as %i: "
 | |
|           ERROR_DETAILS, max_height, codec, device_index, status);
 | |
|       max_height = 4096;
 | |
|     } else if (max_height < 4096) {
 | |
|       GST_WARNING ("max height %d is less than expected value", max_height);
 | |
|       max_height = 4096;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_WIDTH_MIN;
 | |
|     if ((status = NvEncGetEncodeCaps (enc,
 | |
|                 codec_id, &caps_param, &min_width)) != NV_ENC_SUCCESS) {
 | |
|       GST_WARNING ("could not query min width, setting as %i: "
 | |
|           ERROR_DETAILS, min_width, codec, device_index, status);
 | |
|       min_width = 16;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_HEIGHT_MIN;
 | |
|     if ((status = NvEncGetEncodeCaps (enc,
 | |
|                 codec_id, &caps_param, &min_height)) != NV_ENC_SUCCESS) {
 | |
|       GST_WARNING ("could not query min height, setting as %i: "
 | |
|           ERROR_DETAILS, min_height, codec, device_index, status);
 | |
|       min_height = 16;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES;
 | |
|     if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
 | |
|             &device_caps.rc_modes) != NV_ENC_SUCCESS) {
 | |
|       device_caps.rc_modes = 0;
 | |
|     } else {
 | |
|       GST_DEBUG ("[device-%d %s] rate control modes: 0x%x",
 | |
|           device_index, codec, device_caps.rc_modes);
 | |
| #define IS_SUPPORTED_RC(rc_modes,mode) \
 | |
|       ((((rc_modes) & (mode)) == mode) ? "supported" : "not supported")
 | |
| 
 | |
|       GST_DEBUG ("\tconst-qp:         %s",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_CONSTQP));
 | |
|       GST_DEBUG ("\tvbr:              %s",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_VBR));
 | |
|       GST_DEBUG ("\tcbr:              %s",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_CBR));
 | |
|       GST_DEBUG ("\tcbr-lowdelay-hq:  %s",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes,
 | |
|               NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ));
 | |
|       GST_DEBUG ("\tcbr-hq:           %s",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_CBR_HQ));
 | |
|       GST_DEBUG ("\tvbr-hq:           %s",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_VBR_HQ));
 | |
|       GST_DEBUG ("\tvbr-minqp:        %s (deprecated)",
 | |
|           IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_VBR_MINQP));
 | |
| #undef IS_SUPPORTED_RC
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION;
 | |
|     if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
 | |
|             &device_caps.weighted_prediction) != NV_ENC_SUCCESS) {
 | |
|       device_caps.weighted_prediction = FALSE;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE;
 | |
|     if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
 | |
|             &device_caps.custom_vbv_bufsize) != NV_ENC_SUCCESS) {
 | |
|       device_caps.custom_vbv_bufsize = FALSE;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_LOOKAHEAD;
 | |
|     if (NvEncGetEncodeCaps (enc,
 | |
|             codec_id, &caps_param, &device_caps.lookahead) != NV_ENC_SUCCESS) {
 | |
|       device_caps.lookahead = FALSE;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ;
 | |
|     if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
 | |
|             &device_caps.temporal_aq) != NV_ENC_SUCCESS) {
 | |
|       device_caps.temporal_aq = FALSE;
 | |
|     }
 | |
| 
 | |
|     caps_param.capsToQuery = NV_ENC_CAPS_NUM_MAX_BFRAMES;
 | |
|     if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
 | |
|             &device_caps.bframes) != NV_ENC_SUCCESS) {
 | |
|       device_caps.bframes = 0;
 | |
|     }
 | |
| 
 | |
|     DEBUG_DEVICE_CAPS (device_index,
 | |
|         codec, "weighted prediction", device_caps.weighted_prediction);
 | |
| 
 | |
|     DEBUG_DEVICE_CAPS (device_index, codec, "custom vbv-buffer-size",
 | |
|         device_caps.custom_vbv_bufsize);
 | |
| 
 | |
|     DEBUG_DEVICE_CAPS (device_index, codec, "rc-loockahead",
 | |
|         device_caps.lookahead);
 | |
| 
 | |
|     DEBUG_DEVICE_CAPS (device_index, codec, "temporal adaptive quantization",
 | |
|         device_caps.temporal_aq);
 | |
| 
 | |
|     GST_DEBUG ("[device-%d %s] max bframes: %d", device_index, codec,
 | |
|         device_caps.bframes);
 | |
| 
 | |
|     interlace_modes = gst_nvenc_get_interlace_modes (enc, codec_id);
 | |
| 
 | |
|     sink_templ = gst_caps_new_empty_simple ("video/x-raw");
 | |
|     gst_caps_set_value (sink_templ, "format", formats);
 | |
| 
 | |
|     gst_caps_set_simple (sink_templ,
 | |
|         "width", GST_TYPE_INT_RANGE, min_width, max_width,
 | |
|         "height", GST_TYPE_INT_RANGE, min_height, max_height,
 | |
|         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
 | |
| 
 | |
|     if (interlace_modes) {
 | |
|       gst_caps_set_value (sink_templ, "interlace-mode", interlace_modes);
 | |
|       g_value_unset (interlace_modes);
 | |
|       g_free (interlace_modes);
 | |
|     }
 | |
| 
 | |
|     {
 | |
|       GstCaps *cuda_caps = gst_caps_copy (sink_templ);
 | |
| #if HAVE_NVCODEC_GST_GL
 | |
|       GstCaps *gl_caps = gst_caps_copy (sink_templ);
 | |
|       gst_caps_set_features_simple (gl_caps,
 | |
|           gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
 | |
|       gst_caps_append (sink_templ, gl_caps);
 | |
| #endif
 | |
| 
 | |
|       gst_caps_set_features_simple (cuda_caps,
 | |
|           gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY));
 | |
|       gst_caps_append (sink_templ, cuda_caps);
 | |
|     }
 | |
| 
 | |
|     name = g_strdup_printf ("video/x-%s", codec);
 | |
|     src_templ = gst_caps_new_simple (name,
 | |
|         "width", GST_TYPE_INT_RANGE, min_width, max_width,
 | |
|         "height", GST_TYPE_INT_RANGE, min_height, max_height,
 | |
|         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
 | |
|         "stream-format", G_TYPE_STRING, "byte-stream",
 | |
|         "alignment", G_TYPE_STRING, "au", NULL);
 | |
|     gst_caps_set_value (src_templ, "profile", profiles);
 | |
|     g_free (name);
 | |
| 
 | |
|     GST_DEBUG ("sink template caps %" GST_PTR_FORMAT, sink_templ);
 | |
|     GST_DEBUG ("src template caps %" GST_PTR_FORMAT, src_templ);
 | |
| 
 | |
|     g_value_unset (profiles);
 | |
|     g_free (profiles);
 | |
| 
 | |
|   free_format:
 | |
|     if (formats) {
 | |
|       g_value_unset (formats);
 | |
|       g_free (formats);
 | |
|     }
 | |
|     /* fall-through */
 | |
| 
 | |
|   enc_free:
 | |
|     NvEncDestroyEncoder (enc);
 | |
|     CuCtxPopCurrent (NULL);
 | |
|     /* fall-through */
 | |
| 
 | |
|   done:
 | |
|     if (sink_templ && src_templ) {
 | |
|       if (gst_nvenc_cmp_guid (codec_id, NV_ENC_CODEC_H264_GUID)) {
 | |
|         gst_nv_h264_enc_register (plugin, device_index, rank, sink_templ,
 | |
|             src_templ, &device_caps);
 | |
|       } else if (gst_nvenc_cmp_guid (codec_id, NV_ENC_CODEC_HEVC_GUID)) {
 | |
|         gst_nv_h265_enc_register (plugin, device_index, rank, sink_templ,
 | |
|             src_templ, &device_caps);
 | |
|       } else {
 | |
|         g_assert_not_reached ();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     gst_clear_caps (&sink_templ);
 | |
|     gst_clear_caps (&src_templ);
 | |
|   }
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   gint major;
 | |
|   gint minor;
 | |
| } GstNvEncVersion;
 | |
| 
 | |
| gboolean
 | |
| gst_nvenc_load_library (guint * api_major_ver, guint * api_minor_ver)
 | |
| {
 | |
|   GModule *module;
 | |
|   NVENCSTATUS ret = NV_ENC_SUCCESS;
 | |
|   uint32_t max_supported_version;
 | |
|   gint major_ver, minor_ver;
 | |
|   gint i;
 | |
|   static const GstNvEncVersion version_list[] = {
 | |
|     {NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION},
 | |
|     {9, 0},
 | |
|     {GST_NVENC_MIN_API_MAJOR_VERSION, GST_NVENC_MIN_API_MINOR_VERSION}
 | |
|   };
 | |
| 
 | |
|   module = g_module_open (NVENC_LIBRARY_NAME, G_MODULE_BIND_LAZY);
 | |
|   if (module == NULL) {
 | |
|     GST_WARNING ("Could not open library %s, %s",
 | |
|         NVENC_LIBRARY_NAME, g_module_error ());
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (!g_module_symbol (module, "NvEncodeAPICreateInstance",
 | |
|           (gpointer *) & nvEncodeAPICreateInstance)) {
 | |
|     GST_ERROR ("%s", g_module_error ());
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (!g_module_symbol (module, "NvEncodeAPIGetMaxSupportedVersion",
 | |
|           (gpointer *) & nvEncodeAPIGetMaxSupportedVersion)) {
 | |
|     GST_ERROR ("NvEncodeAPIGetMaxSupportedVersion unavailable");
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   /* WARNING: Any developers who want to bump SDK version must ensure that
 | |
|    * following macro values were not changed and also need to check ABI compatibility.
 | |
|    * Otherwise, gst_nvenc_get_ helpers also should be updated.
 | |
|    * Currently SDK 8.1 and 9.0 compatible
 | |
|    *
 | |
|    * NVENCAPI_VERSION (NVENCAPI_MAJOR_VERSION | (NVENCAPI_MINOR_VERSION << 24))
 | |
|    *
 | |
|    * NVENCAPI_STRUCT_VERSION(ver) ((uint32_t)NVENCAPI_VERSION | ((ver)<<16) | (0x7 << 28))
 | |
|    *
 | |
|    * NV_ENC_CAPS_PARAM_VER                NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_ENCODE_OUT_PARAMS_VER         NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_CREATE_INPUT_BUFFER_VER       NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_CREATE_BITSTREAM_BUFFER_VER   NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_CREATE_MV_BUFFER_VER          NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_RC_PARAMS_VER                 NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_CONFIG_VER                   (NVENCAPI_STRUCT_VERSION(7) | ( 1<<31 ))
 | |
|    * NV_ENC_INITIALIZE_PARAMS_VER        (NVENCAPI_STRUCT_VERSION(5) | ( 1<<31 ))
 | |
|    * NV_ENC_RECONFIGURE_PARAMS_VER       (NVENCAPI_STRUCT_VERSION(1) | ( 1<<31 ))
 | |
|    * NV_ENC_PRESET_CONFIG_VER            (NVENCAPI_STRUCT_VERSION(4) | ( 1<<31 ))
 | |
|    * NV_ENC_PIC_PARAMS_VER               (NVENCAPI_STRUCT_VERSION(4) | ( 1<<31 ))
 | |
|    * NV_ENC_MEONLY_PARAMS_VER             NVENCAPI_STRUCT_VERSION(3)
 | |
|    * NV_ENC_LOCK_BITSTREAM_VER            NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_LOCK_INPUT_BUFFER_VER         NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_MAP_INPUT_RESOURCE_VER        NVENCAPI_STRUCT_VERSION(4)
 | |
|    * NV_ENC_REGISTER_RESOURCE_VER         NVENCAPI_STRUCT_VERSION(3)
 | |
|    * NV_ENC_STAT_VER                      NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER    NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_EVENT_PARAMS_VER              NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER NVENCAPI_STRUCT_VERSION(1)
 | |
|    * NV_ENCODE_API_FUNCTION_LIST_VER      NVENCAPI_STRUCT_VERSION(2)
 | |
|    */
 | |
| 
 | |
|   ret = nvEncodeAPIGetMaxSupportedVersion (&max_supported_version);
 | |
| 
 | |
|   if (ret != NV_ENC_SUCCESS) {
 | |
|     GST_ERROR ("Could not query max supported api version, ret %d", ret);
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   /* 4 LSB: minor version
 | |
|    * the rest: major version */
 | |
|   major_ver = max_supported_version >> 4;
 | |
|   minor_ver = max_supported_version & 0xf;
 | |
| 
 | |
|   GST_INFO ("Maximum supported API version by driver: %d.%d",
 | |
|       major_ver, minor_ver);
 | |
| 
 | |
|   ret = NV_ENC_ERR_INVALID_VERSION;
 | |
|   for (i = 0; i < G_N_ELEMENTS (version_list); i++) {
 | |
|     if (version_list[i].major > major_ver ||
 | |
|         (version_list[i].major == major_ver
 | |
|             && version_list[i].minor > minor_ver)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     gst_nvenc_api_version =
 | |
|         GST_NVENCAPI_VERSION (version_list[i].major, version_list[i].minor);
 | |
| 
 | |
|     nvenc_api.version = GST_NVENCAPI_STRUCT_VERSION (2, gst_nvenc_api_version);
 | |
|     ret = nvEncodeAPICreateInstance (&nvenc_api);
 | |
| 
 | |
|     if (ret == NV_ENC_SUCCESS) {
 | |
|       GST_INFO ("API version %d.%d load done",
 | |
|           version_list[i].major, version_list[i].minor);
 | |
| 
 | |
|       *api_major_ver = version_list[i].major;
 | |
|       *api_minor_ver = version_list[i].minor;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret == NV_ENC_SUCCESS;
 | |
| }
 | |
| 
 | |
| void
 | |
| gst_nvenc_plugin_init (GstPlugin * plugin, guint device_index,
 | |
|     CUcontext cuda_ctx)
 | |
| {
 | |
|   gst_nv_enc_register (plugin, NV_ENC_CODEC_H264_GUID,
 | |
|       "h264", GST_RANK_PRIMARY * 2, device_index, cuda_ctx);
 | |
|   gst_nv_enc_register (plugin, NV_ENC_CODEC_HEVC_GUID,
 | |
|       "h265", GST_RANK_PRIMARY * 2, device_index, cuda_ctx);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_api_version (void)
 | |
| {
 | |
|   /* NVENCAPI_VERSION == (NVENCAPI_MAJOR_VERSION | (NVENCAPI_MINOR_VERSION << 24)) */
 | |
|   return gst_nvenc_api_version;
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_caps_param_version (void)
 | |
| {
 | |
|   /* NV_ENC_CAPS_PARAM_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_encode_out_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_ENCODE_OUT_PARAMS_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_create_input_buffer_version (void)
 | |
| {
 | |
|   /* NV_ENC_CREATE_INPUT_BUFFER_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_create_bitstream_buffer_version (void)
 | |
| {
 | |
|   /* NV_ENC_CREATE_BITSTREAM_BUFFER_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_create_mv_buffer_version (void)
 | |
| {
 | |
|   /* NV_ENC_CREATE_MV_BUFFER_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_rc_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_RC_PARAMS_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_config_version (void)
 | |
| {
 | |
|   /* NV_ENC_CONFIG_VER ==
 | |
|    *   (NVENCAPI_STRUCT_VERSION(7) | ( 1<<31 )) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (7, gst_nvenc_api_version) | (1 << 31);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_initialize_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_INITIALIZE_PARAMS_VER ==
 | |
|    *   (NVENCAPI_STRUCT_VERSION(5) | ( 1<<31 )) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (5, gst_nvenc_api_version) | (1 << 31);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_reconfigure_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_RECONFIGURE_PARAMS_VER ==
 | |
|    *   (NVENCAPI_STRUCT_VERSION(1) | ( 1<<31 )) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version) | (1 << 31);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_preset_config_version (void)
 | |
| {
 | |
|   /* NV_ENC_PRESET_CONFIG_VER ==
 | |
|    *   (NVENCAPI_STRUCT_VERSION(4) | ( 1<<31 )) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (4, gst_nvenc_api_version) | (1 << 31);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_pic_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_PIC_PARAMS_VER ==
 | |
|    *  (NVENCAPI_STRUCT_VERSION(4) | ( 1<<31 )) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (4, gst_nvenc_api_version) | (1 << 31);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_meonly_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_MEONLY_PARAMS_VER == NVENCAPI_STRUCT_VERSION(3) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (3, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_lock_bitstream_version (void)
 | |
| {
 | |
|   /* NV_ENC_LOCK_BITSTREAM_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_lock_input_buffer_version (void)
 | |
| {
 | |
|   /* NV_ENC_LOCK_INPUT_BUFFER_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_map_input_resource_version (void)
 | |
| {
 | |
|   /* NV_ENC_MAP_INPUT_RESOURCE_VER == NVENCAPI_STRUCT_VERSION(4) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (4, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_register_resource_version (void)
 | |
| {
 | |
|   /* NV_ENC_REGISTER_RESOURCE_VER == NVENCAPI_STRUCT_VERSION(3) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (3, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_stat_version (void)
 | |
| {
 | |
|   /* NV_ENC_STAT_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_sequence_param_payload_version (void)
 | |
| {
 | |
|   /* NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_event_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_EVENT_PARAMS_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 | |
| 
 | |
| guint32
 | |
| gst_nvenc_get_open_encode_session_ex_params_version (void)
 | |
| {
 | |
|   /* NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER == NVENCAPI_STRUCT_VERSION(1) */
 | |
|   return GST_NVENCAPI_STRUCT_VERSION (1, gst_nvenc_api_version);
 | |
| }
 |