mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
60735deded
Adding new encoder elements nvd3d11{h264,h265}enc for Direct3D11 input support and re-written nvcuda{h264,h265}enc elements. Newly writeen elements have some differences compared with old nv{h264,h265}enc including non-backward compatible changes. * RGBA is not a supported input format any more: New elements will support only YUV formats to avoid implicit conversion done by hardware. Ideally it should be done by upstream element in order to have more control on it. Moreover, RGBA support can cause redundant RGBA -> YUV conversion if multiple encoders are used for the same RGBA input * Subsampled planar format support is dropped: I420 and YV12 format are not supported formats for Direct3D11. Although it's supported in CUDA mode, it's not a hardware friendly memory layout and it will waste GPU memory since UV planes will have large padding due to the memory layout requirement of NVENC. * GL support is dropped: Similar to the RGBA case, GL support in encoder would be suboptimal if GL input is used by multiple encoders, because each encoder will copy GL memory into CUDA memory. Upstream cudaupload element can be used for GL <-> CUDA interop instead. * No more pre-allocation of encoder input surfaces. New implementation will use input CUDA memory without copy (zero-copy) or will copy into a NVENC's input buffer struct in case of system memory input. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1997>
1143 lines
36 KiB
C
1143 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 "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);
|
|
}
|
|
|
|
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);
|
|
}
|