mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
nvenc: add preset selection
Some presets are not always supported on all devices and will cause an error if used. Specifically, the LOSSLESS presets are known to not work everywhere.
This commit is contained in:
parent
ac8a14d1c8
commit
c45fc2ef53
4 changed files with 141 additions and 4 deletions
|
@ -50,6 +50,55 @@
|
|||
#define parent_class gst_nv_base_enc_parent_class
|
||||
G_DEFINE_ABSTRACT_TYPE (GstNvBaseEnc, gst_nv_base_enc, GST_TYPE_VIDEO_ENCODER);
|
||||
|
||||
#define GST_TYPE_NV_PRESET (gst_nv_preset_get_type())
|
||||
static GType
|
||||
gst_nv_preset_get_type (void)
|
||||
{
|
||||
static GType nv_preset_type = 0;
|
||||
|
||||
static const GEnumValue presets[] = {
|
||||
{GST_NV_PRESET_DEFAULT, "Default", "default"},
|
||||
{GST_NV_PRESET_HP, "High Performance", "hp"},
|
||||
{GST_NV_PRESET_HQ, "High Quality", "hq"},
|
||||
/* {GST_NV_PRESET_BD, "BD", "bd"}, */
|
||||
{GST_NV_PRESET_LOW_LATENCY_DEFAULT, "Low Latency", "low-latency"},
|
||||
{GST_NV_PRESET_LOW_LATENCY_HQ, "Low Latency, High Quality",
|
||||
"low-latency-hq"},
|
||||
{GST_NV_PRESET_LOW_LATENCY_HP, "Low Latency, High Performance",
|
||||
"low-latency-hp"},
|
||||
{GST_NV_PRESET_LOSSLESS_DEFAULT, "Lossless", "lossless"},
|
||||
{GST_NV_PRESET_LOSSLESS_HP, "Lossless, High Performance", "lossless-hp"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!nv_preset_type) {
|
||||
nv_preset_type = g_enum_register_static ("GstNvPreset", presets);
|
||||
}
|
||||
return nv_preset_type;
|
||||
}
|
||||
|
||||
static GUID
|
||||
_nv_preset_to_guid (GstNvPreset preset)
|
||||
{
|
||||
GUID null = { 0, };
|
||||
|
||||
switch (preset) {
|
||||
#define CASE(gst,nv) case G_PASTE(GST_NV_PRESET_,gst): return G_PASTE(G_PASTE(NV_ENC_PRESET_,nv),_GUID)
|
||||
CASE (DEFAULT, DEFAULT);
|
||||
CASE (HP, HP);
|
||||
CASE (HQ, HQ);
|
||||
/* CASE (BD, BD);*/
|
||||
CASE (LOW_LATENCY_DEFAULT, LOW_LATENCY_DEFAULT);
|
||||
CASE (LOW_LATENCY_HQ, LOW_LATENCY_HQ);
|
||||
CASE (LOW_LATENCY_HP, LOW_LATENCY_HQ);
|
||||
CASE (LOSSLESS_DEFAULT, LOSSLESS_DEFAULT);
|
||||
CASE (LOSSLESS_HP, LOSSLESS_HP);
|
||||
#undef CASE
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
|
@ -71,8 +120,11 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
PROP_DEVICE_ID,
|
||||
PROP_PRESET,
|
||||
};
|
||||
|
||||
#define DEFAULT_PRESET GST_NV_PRESET_DEFAULT
|
||||
|
||||
/* This lock is needed to prevent the situation where multiple encoders are
|
||||
* initialised at the same time which appears to cause excessive CPU usage over
|
||||
* some period of time. */
|
||||
|
@ -154,6 +206,11 @@ gst_nv_base_enc_class_init (GstNvBaseEncClass * klass)
|
|||
"Cuda Device ID",
|
||||
"Set the GPU device to use for operations",
|
||||
0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_PRESET,
|
||||
g_param_spec_enum ("preset", "Encoding Preset",
|
||||
"Encoding Preset",
|
||||
GST_TYPE_NV_PRESET,
|
||||
DEFAULT_PRESET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -517,6 +574,9 @@ gst_nv_base_enc_init (GstNvBaseEnc * nvenc)
|
|||
{
|
||||
GstVideoEncoder *encoder = GST_VIDEO_ENCODER (nvenc);
|
||||
|
||||
nvenc->preset_enum = DEFAULT_PRESET;
|
||||
nvenc->selected_preset = _nv_preset_to_guid (nvenc->preset_enum);
|
||||
|
||||
GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
|
||||
GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
|
||||
}
|
||||
|
@ -1590,6 +1650,10 @@ gst_nv_base_enc_set_property (GObject * object, guint prop_id,
|
|||
case PROP_DEVICE_ID:
|
||||
nvenc->cuda_device_id = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_PRESET:
|
||||
nvenc->preset_enum = g_value_get_enum (value);
|
||||
nvenc->selected_preset = _nv_preset_to_guid (nvenc->preset_enum);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1606,6 +1670,9 @@ gst_nv_base_enc_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
case PROP_DEVICE_ID:
|
||||
g_value_set_uint (value, nvenc->cuda_device_id);
|
||||
break;
|
||||
case PROP_PRESET:
|
||||
g_value_set_enum (value, nvenc->preset_enum);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -37,11 +37,25 @@
|
|||
#define GST_IS_NV_BASE_ENC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NV_BASE_ENC))
|
||||
|
||||
typedef enum {
|
||||
GST_NV_PRESET_DEFAULT,
|
||||
GST_NV_PRESET_HP,
|
||||
GST_NV_PRESET_HQ,
|
||||
/* FIXME: problematic GST_NV_PRESET_BD, */
|
||||
GST_NV_PRESET_LOW_LATENCY_DEFAULT,
|
||||
GST_NV_PRESET_LOW_LATENCY_HQ,
|
||||
GST_NV_PRESET_LOW_LATENCY_HP,
|
||||
GST_NV_PRESET_LOSSLESS_DEFAULT,
|
||||
GST_NV_PRESET_LOSSLESS_HP,
|
||||
} GstNvPreset;
|
||||
|
||||
typedef struct {
|
||||
GstVideoEncoder video_encoder;
|
||||
|
||||
/* properties */
|
||||
guint cuda_device_id;
|
||||
GstNvPreset preset_enum;
|
||||
GUID selected_preset;
|
||||
|
||||
CUcontext cuda_ctx;
|
||||
void * encoder;
|
||||
|
|
|
@ -77,6 +77,24 @@ NvEncGetInputFormats (void *encoder, GUID enc_guid,
|
|||
return nvenc_api.nvEncGetInputFormats (encoder, enc_guid, array, size, num);
|
||||
}
|
||||
|
||||
NVENCSTATUS
|
||||
NvEncGetEncodePresetCount (void *encoder, GUID encodeGUID,
|
||||
uint32_t * encodePresetGUIDCount)
|
||||
{
|
||||
g_assert (nvenc_api.nvEncGetEncodeProfileGUIDCount != NULL);
|
||||
return nvenc_api.nvEncGetEncodePresetCount (encoder, encodeGUID,
|
||||
encodePresetGUIDCount);
|
||||
}
|
||||
|
||||
NVENCSTATUS
|
||||
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
|
||||
NvEncGetEncodePresetConfig (void *encoder, GUID encodeGUID,
|
||||
GUID presetGUID, NV_ENC_PRESET_CONFIG * presetConfig)
|
||||
|
|
|
@ -423,6 +423,7 @@ gst_nv_h264_enc_initialize_encoder (GstNvBaseEnc * nvenc,
|
|||
GstVideoInfo *info = &state->info;
|
||||
GstCaps *allowed_caps, *template_caps;
|
||||
GUID selected_profile = NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID;
|
||||
GUID selected_preset = nvenc->selected_preset;
|
||||
int level_idc = NV_ENC_LEVEL_AUTOSELECT;
|
||||
|
||||
/* TODO: support reconfiguration */
|
||||
|
@ -485,8 +486,45 @@ gst_nv_h264_enc_initialize_encoder (GstNvBaseEnc * nvenc,
|
|||
params->encodeGUID = NV_ENC_CODEC_H264_GUID;
|
||||
params->encodeWidth = GST_VIDEO_INFO_WIDTH (info);
|
||||
params->encodeHeight = GST_VIDEO_INFO_HEIGHT (info);
|
||||
/* FIXME: make this a property */
|
||||
params->presetGUID = NV_ENC_PRESET_HP_GUID; // _DEFAULT
|
||||
|
||||
{
|
||||
guint32 n_presets;
|
||||
GUID *presets;
|
||||
guint32 i;
|
||||
|
||||
nv_ret =
|
||||
NvEncGetEncodePresetCount (GST_NV_BASE_ENC (h264enc)->encoder,
|
||||
params->encodeGUID, &n_presets);
|
||||
if (nv_ret != NV_ENC_SUCCESS) {
|
||||
GST_ELEMENT_ERROR (h264enc, LIBRARY, SETTINGS, (NULL),
|
||||
("Failed to get encoder presets"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
presets = g_new0 (GUID, n_presets);
|
||||
nv_ret =
|
||||
NvEncGetEncodePresetGUIDs (GST_NV_BASE_ENC (h264enc)->encoder,
|
||||
params->encodeGUID, presets, n_presets, &n_presets);
|
||||
if (nv_ret != NV_ENC_SUCCESS) {
|
||||
GST_ELEMENT_ERROR (h264enc, LIBRARY, SETTINGS, (NULL),
|
||||
("Failed to get encoder presets"));
|
||||
g_free (presets);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_presets; i++) {
|
||||
if (gst_nvenc_cmp_guid (presets[i], selected_preset))
|
||||
break;
|
||||
}
|
||||
g_free (presets);
|
||||
if (i >= n_presets) {
|
||||
GST_ELEMENT_ERROR (h264enc, LIBRARY, SETTINGS, (NULL),
|
||||
("Selected preset not supported"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
params->presetGUID = selected_preset;
|
||||
}
|
||||
params->enablePTD = 1;
|
||||
if (!old_state) {
|
||||
/* this sets the required buffer size and the maximum allowed size on
|
||||
|
@ -531,8 +569,8 @@ gst_nv_h264_enc_initialize_encoder (GstNvBaseEnc * nvenc,
|
|||
preset_config.presetCfg.encodeCodecConfig.h264Config.chromaFormatIDC = 1;
|
||||
if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444) {
|
||||
GST_DEBUG_OBJECT (h264enc, "have Y444 input, setting config accordingly");
|
||||
preset_config.presetCfg.encodeCodecConfig.
|
||||
h264Config.separateColourPlaneFlag = 1;
|
||||
preset_config.presetCfg.encodeCodecConfig.h264Config.
|
||||
separateColourPlaneFlag = 1;
|
||||
preset_config.presetCfg.encodeCodecConfig.h264Config.chromaFormatIDC = 3;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue