nvenc: Add more rate-control options

New rate-control modes are introduced (if device can support)
* cbr-ld-hr: CBR low-delay high quality
* cbr-hq: CBR high quality
* vbr-hq: VBR high quality

Also, various configurable rate-control related properties are added.
This commit is contained in:
Seungha Yang 2019-09-03 21:33:15 +09:00
parent ea19a7c715
commit 81272eaa82
5 changed files with 467 additions and 38 deletions

View file

@ -106,13 +106,17 @@ gst_nv_rc_mode_get_type (void)
static GType nv_rc_mode_type = 0; static GType nv_rc_mode_type = 0;
static const GEnumValue modes[] = { static const GEnumValue modes[] = {
{GST_NV_RC_MODE_DEFAULT, "Default (from NVENC preset)", "default"}, {GST_NV_RC_MODE_DEFAULT, "Default", "default"},
{GST_NV_RC_MODE_CONSTQP, "Constant Quantization", "constqp"}, {GST_NV_RC_MODE_CONSTQP, "Constant Quantization", "constqp"},
{GST_NV_RC_MODE_CBR, "Constant Bit Rate", "cbr"}, {GST_NV_RC_MODE_CBR, "Constant Bit Rate", "cbr"},
{GST_NV_RC_MODE_VBR, "Variable Bit Rate", "vbr"}, {GST_NV_RC_MODE_VBR, "Variable Bit Rate", "vbr"},
{GST_NV_RC_MODE_VBR_MINQP, {GST_NV_RC_MODE_VBR_MINQP,
"Variable Bit Rate (with minimum quantization parameter)", "Variable Bit Rate "
"vbr-minqp"}, "(with minimum quantization parameter, DEPRECATED)", "vbr-minqp"},
{GST_NV_RC_MODE_CBR_LOWDELAY_HQ,
"Low-Delay CBR, High Quality", "cbr-ld-hq"},
{GST_NV_RC_MODE_CBR_HQ, "CBR, High Quality (slower)", "cbr-hq"},
{GST_NV_RC_MODE_VBR_HQ, "VBR, High Quality (slower)", "vbr-hq"},
{0, NULL, NULL}, {0, NULL, NULL},
}; };
@ -127,15 +131,18 @@ _rc_mode_to_nv (GstNvRCMode mode)
{ {
switch (mode) { switch (mode) {
case GST_NV_RC_MODE_DEFAULT: case GST_NV_RC_MODE_DEFAULT:
return -1; return NV_ENC_PARAMS_RC_VBR;
#define CASE(gst,nv) case G_PASTE(GST_NV_RC_MODE_,gst): return G_PASTE(NV_ENC_PARAMS_RC_,nv) #define CASE(gst,nv) case G_PASTE(GST_NV_RC_MODE_,gst): return G_PASTE(NV_ENC_PARAMS_RC_,nv)
CASE (CONSTQP, CONSTQP); CASE (CONSTQP, CONSTQP);
CASE (CBR, CBR); CASE (CBR, CBR);
CASE (VBR, VBR); CASE (VBR, VBR);
CASE (VBR_MINQP, VBR_MINQP); CASE (VBR_MINQP, VBR_MINQP);
CASE (CBR_LOWDELAY_HQ, CBR_LOWDELAY_HQ);
CASE (CBR_HQ, CBR_HQ);
CASE (VBR_HQ, VBR_HQ);
#undef CASE #undef CASE
default: default:
return -1; return NV_ENC_PARAMS_RC_VBR;
} }
} }
@ -150,6 +157,14 @@ enum
PROP_QP_MAX, PROP_QP_MAX,
PROP_QP_CONST, PROP_QP_CONST,
PROP_GOP_SIZE, PROP_GOP_SIZE,
PROP_MAX_BITRATE,
PROP_SPATIAL_AQ,
PROP_AQ_STRENGTH,
PROP_NON_REF_P,
PROP_ZEROLATENCY,
PROP_STRICT_GOP,
PROP_CONST_QUALITY,
PROP_I_ADAPT,
}; };
#define DEFAULT_PRESET GST_NV_PRESET_DEFAULT #define DEFAULT_PRESET GST_NV_PRESET_DEFAULT
@ -159,6 +174,14 @@ enum
#define DEFAULT_QP_MAX -1 #define DEFAULT_QP_MAX -1
#define DEFAULT_QP_CONST -1 #define DEFAULT_QP_CONST -1
#define DEFAULT_GOP_SIZE 75 #define DEFAULT_GOP_SIZE 75
#define DEFAULT_MAX_BITRATE 0
#define DEFAULT_SPATIAL_AQ FALSE
#define DEFAULT_AQ_STRENGTH 0
#define DEFAULT_NON_REF_P FALSE
#define DEFAULT_ZEROLATENCY FALSE
#define DEFAULT_STRICT_GOP FALSE
#define DEFAULT_CONST_QUALITY 0
#define DEFAULT_I_ADAPT FALSE
/* This lock is needed to prevent the situation where multiple encoders are /* 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 * initialised at the same time which appears to cause excessive CPU usage over
@ -285,6 +308,52 @@ gst_nv_base_enc_class_init (GstNvBaseEncClass * klass)
DEFAULT_BITRATE, DEFAULT_BITRATE,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
g_param_spec_uint ("max-bitrate", "Max Bitrate",
"Maximum Bitrate in kbit/sec (ignored for CBR mode)", 0, 2000 * 1024,
DEFAULT_MAX_BITRATE,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SPATIAL_AQ,
g_param_spec_boolean ("spatial-aq", "Spatial AQ",
"Spatial Adaptive Quantization",
DEFAULT_SPATIAL_AQ,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_AQ_STRENGTH,
g_param_spec_uint ("aq-strength", "AQ Strength",
"Adaptive Quantization Strength when spatial-aq is enabled"
" from 1 (low) to 15 (aggressive), (0 = autoselect)",
0, 15, DEFAULT_AQ_STRENGTH,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_NON_REF_P,
g_param_spec_boolean ("nonref-p", "Nonref P",
"Automatic insertion of non-reference P-frames", DEFAULT_NON_REF_P,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ZEROLATENCY,
g_param_spec_boolean ("zerolatency", "Zerolatency",
"Zero latency operation (no reordering delay)", DEFAULT_ZEROLATENCY,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_STRICT_GOP,
g_param_spec_boolean ("strict-gop", "Strict GOP",
"Minimize GOP-to-GOP rate fluctuations", DEFAULT_STRICT_GOP,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CONST_QUALITY,
g_param_spec_double ("const-quality", "Constant Quality",
"Target Constant Quality level for VBR mode (0 = automatic)",
0, 51, DEFAULT_CONST_QUALITY,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_I_ADAPT,
g_param_spec_boolean ("i-adapt", "I Adapt",
"Enable adaptive I-frame insert when lookahead is enabled",
DEFAULT_I_ADAPT,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
} }
static gboolean static gboolean
@ -713,6 +782,14 @@ gst_nv_base_enc_init (GstNvBaseEnc * nvenc)
nvenc->qp_const = DEFAULT_QP_CONST; nvenc->qp_const = DEFAULT_QP_CONST;
nvenc->bitrate = DEFAULT_BITRATE; nvenc->bitrate = DEFAULT_BITRATE;
nvenc->gop_size = DEFAULT_GOP_SIZE; nvenc->gop_size = DEFAULT_GOP_SIZE;
nvenc->max_bitrate = DEFAULT_MAX_BITRATE;
nvenc->spatial_aq = DEFAULT_SPATIAL_AQ;
nvenc->aq_strength = DEFAULT_AQ_STRENGTH;
nvenc->non_refp = DEFAULT_NON_REF_P;
nvenc->zerolatency = DEFAULT_ZEROLATENCY;
nvenc->strict_gop = DEFAULT_STRICT_GOP;
nvenc->const_quality = DEFAULT_CONST_QUALITY;
nvenc->i_adapt = DEFAULT_I_ADAPT;
GST_VIDEO_ENCODER_STREAM_LOCK (encoder); GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder); GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
@ -1112,6 +1189,83 @@ _get_frame_data_height (GstVideoInfo * info)
return ret; return ret;
} }
static void
gst_nv_base_enc_setup_rate_control (GstNvBaseEnc * nvenc,
NV_ENC_RC_PARAMS * rc_params)
{
GstNvRCMode rc_mode = nvenc->rate_control_mode;
NV_ENC_PARAMS_RC_MODE nv_rcmode;
if (nvenc->bitrate)
rc_params->averageBitRate = nvenc->bitrate * 1024;
if (nvenc->max_bitrate)
rc_params->maxBitRate = nvenc->max_bitrate * 1024;
if (nvenc->vbv_buffersize)
rc_params->vbvBufferSize = nvenc->vbv_buffersize * 1024;
/* Guess the best matching mode */
if (rc_mode == GST_NV_RC_MODE_DEFAULT) {
if (nvenc->qp_const >= 0) {
/* constQP is used only for RC_CONSTQP mode */
rc_mode = GST_NV_RC_MODE_CONSTQP;
}
}
if (nvenc->qp_min >= 0) {
rc_params->enableMinQP = 1;
rc_params->minQP.qpInterB = nvenc->qp_min;
rc_params->minQP.qpInterP = nvenc->qp_min;
rc_params->minQP.qpIntra = nvenc->qp_min;
}
if (nvenc->qp_max >= 0) {
rc_params->enableMaxQP = 1;
rc_params->maxQP.qpInterB = nvenc->qp_max;
rc_params->maxQP.qpInterP = nvenc->qp_max;
rc_params->maxQP.qpIntra = nvenc->qp_max;
}
if (nvenc->qp_const >= 0) {
rc_params->constQP.qpInterB = nvenc->qp_const;
rc_params->constQP.qpInterP = nvenc->qp_const;
rc_params->constQP.qpIntra = nvenc->qp_const;
}
nv_rcmode = _rc_mode_to_nv (rc_mode);
if (nv_rcmode == NV_ENC_PARAMS_RC_VBR_MINQP && nvenc->qp_min < 0) {
GST_WARNING_OBJECT (nvenc, "vbr-minqp was requested without qp-min");
nv_rcmode = NV_ENC_PARAMS_RC_VBR;
}
rc_params->rateControlMode = nv_rcmode;
if (nvenc->spatial_aq) {
rc_params->enableAQ = 1;
rc_params->aqStrength = nvenc->aq_strength;
}
rc_params->enableTemporalAQ = nvenc->temporal_aq;
if (nvenc->rc_lookahead) {
rc_params->enableLookahead = 1;
rc_params->lookaheadDepth = nvenc->rc_lookahead;
rc_params->disableIadapt = !nvenc->i_adapt;
}
rc_params->strictGOPTarget = nvenc->strict_gop;
rc_params->enableNonRefP = nvenc->non_refp;
rc_params->zeroReorderDelay = nvenc->zerolatency;
if (nvenc->const_quality) {
guint scaled = (gint) (nvenc->const_quality * 256.0);
rc_params->targetQuality = (guint8) (scaled >> 8);
rc_params->targetQualityLSB = (guint8) (scaled & 0xff);
}
}
/* GstVideoEncoder::set_format or by nvenc self if new properties were set. /* GstVideoEncoder::set_format or by nvenc self if new properties were set.
* *
* NvEncReconfigureEncoder with following conditions are not allowed * NvEncReconfigureEncoder with following conditions are not allowed
@ -1284,32 +1438,7 @@ gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
params->darHeight = dar_d; params->darHeight = dar_d;
} }
if (nvenc->rate_control_mode != GST_NV_RC_MODE_DEFAULT) { gst_nv_base_enc_setup_rate_control (nvenc, &params->encodeConfig->rcParams);
params->encodeConfig->rcParams.rateControlMode =
_rc_mode_to_nv (nvenc->rate_control_mode);
if (nvenc->bitrate > 0) {
/* FIXME: this produces larger bitrates?! */
params->encodeConfig->rcParams.averageBitRate = nvenc->bitrate * 1024;
params->encodeConfig->rcParams.maxBitRate = nvenc->bitrate * 1024;
}
if (nvenc->qp_const > 0) {
params->encodeConfig->rcParams.constQP.qpInterB = nvenc->qp_const;
params->encodeConfig->rcParams.constQP.qpInterP = nvenc->qp_const;
params->encodeConfig->rcParams.constQP.qpIntra = nvenc->qp_const;
}
if (nvenc->qp_min >= 0) {
params->encodeConfig->rcParams.enableMinQP = 1;
params->encodeConfig->rcParams.minQP.qpInterB = nvenc->qp_min;
params->encodeConfig->rcParams.minQP.qpInterP = nvenc->qp_min;
params->encodeConfig->rcParams.minQP.qpIntra = nvenc->qp_min;
}
if (nvenc->qp_max >= 0) {
params->encodeConfig->rcParams.enableMaxQP = 1;
params->encodeConfig->rcParams.maxQP.qpInterB = nvenc->qp_max;
params->encodeConfig->rcParams.maxQP.qpInterP = nvenc->qp_max;
params->encodeConfig->rcParams.maxQP.qpIntra = nvenc->qp_max;
}
}
params->enableWeightedPrediction = nvenc->weighted_pred; params->enableWeightedPrediction = nvenc->weighted_pred;
@ -2170,6 +2299,8 @@ gst_nv_base_enc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object);
GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (nvenc);
gboolean reconfig = TRUE;
switch (prop_id) { switch (prop_id) {
case PROP_PRESET: case PROP_PRESET:
@ -2178,33 +2309,66 @@ gst_nv_base_enc_set_property (GObject * object, guint prop_id,
gst_nv_base_enc_schedule_reconfig (nvenc); gst_nv_base_enc_schedule_reconfig (nvenc);
break; break;
case PROP_RC_MODE: case PROP_RC_MODE:
nvenc->rate_control_mode = g_value_get_enum (value); {
gst_nv_base_enc_schedule_reconfig (nvenc); GstNvRCMode rc_mode = g_value_get_enum (value);
NV_ENC_PARAMS_RC_MODE nv_rc_mode = _rc_mode_to_nv (rc_mode);
if ((klass->device_caps.rc_modes & nv_rc_mode) == nv_rc_mode) {
nvenc->rate_control_mode = rc_mode;
} else {
GST_WARNING_OBJECT (nvenc,
"device does not support requested rate control mode %d", rc_mode);
reconfig = FALSE;
}
break; break;
}
case PROP_QP_MIN: case PROP_QP_MIN:
nvenc->qp_min = g_value_get_int (value); nvenc->qp_min = g_value_get_int (value);
gst_nv_base_enc_schedule_reconfig (nvenc);
break; break;
case PROP_QP_MAX: case PROP_QP_MAX:
nvenc->qp_max = g_value_get_int (value); nvenc->qp_max = g_value_get_int (value);
gst_nv_base_enc_schedule_reconfig (nvenc);
break; break;
case PROP_QP_CONST: case PROP_QP_CONST:
nvenc->qp_const = g_value_get_int (value); nvenc->qp_const = g_value_get_int (value);
gst_nv_base_enc_schedule_reconfig (nvenc);
break; break;
case PROP_BITRATE: case PROP_BITRATE:
nvenc->bitrate = g_value_get_uint (value); nvenc->bitrate = g_value_get_uint (value);
gst_nv_base_enc_schedule_reconfig (nvenc);
break; break;
case PROP_GOP_SIZE: case PROP_GOP_SIZE:
nvenc->gop_size = g_value_get_int (value); nvenc->gop_size = g_value_get_int (value);
gst_nv_base_enc_schedule_reconfig (nvenc); break;
case PROP_MAX_BITRATE:
nvenc->max_bitrate = g_value_get_uint (value);
break;
case PROP_SPATIAL_AQ:
nvenc->spatial_aq = g_value_get_boolean (value);
break;
case PROP_AQ_STRENGTH:
nvenc->aq_strength = g_value_get_uint (value);
break;
case PROP_NON_REF_P:
nvenc->non_refp = g_value_get_boolean (value);
break;
case PROP_ZEROLATENCY:
nvenc->zerolatency = g_value_get_boolean (value);
break;
case PROP_STRICT_GOP:
nvenc->strict_gop = g_value_get_boolean (value);
break;
case PROP_CONST_QUALITY:
nvenc->const_quality = g_value_get_double (value);
break;
case PROP_I_ADAPT:
nvenc->i_adapt = g_value_get_boolean (value);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
reconfig = FALSE;
break; break;
} }
if (reconfig)
gst_nv_base_enc_schedule_reconfig (nvenc);
} }
static void static void
@ -2239,6 +2403,30 @@ gst_nv_base_enc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_GOP_SIZE: case PROP_GOP_SIZE:
g_value_set_int (value, nvenc->gop_size); g_value_set_int (value, nvenc->gop_size);
break; break;
case PROP_MAX_BITRATE:
g_value_set_uint (value, nvenc->max_bitrate);
break;
case PROP_SPATIAL_AQ:
g_value_set_boolean (value, nvenc->spatial_aq);
break;
case PROP_AQ_STRENGTH:
g_value_set_uint (value, nvenc->aq_strength);
break;
case PROP_NON_REF_P:
g_value_set_boolean (value, nvenc->non_refp);
break;
case PROP_ZEROLATENCY:
g_value_set_boolean (value, nvenc->zerolatency);
break;
case PROP_STRICT_GOP:
g_value_set_boolean (value, nvenc->strict_gop);
break;
case PROP_CONST_QUALITY:
g_value_set_double (value, nvenc->const_quality);
break;
case PROP_I_ADAPT:
g_value_set_boolean (value, nvenc->i_adapt);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -56,10 +56,17 @@ typedef enum {
GST_NV_RC_MODE_CBR, GST_NV_RC_MODE_CBR,
GST_NV_RC_MODE_VBR, GST_NV_RC_MODE_VBR,
GST_NV_RC_MODE_VBR_MINQP, GST_NV_RC_MODE_VBR_MINQP,
GST_NV_RC_MODE_CBR_LOWDELAY_HQ,
GST_NV_RC_MODE_CBR_HQ,
GST_NV_RC_MODE_VBR_HQ,
} GstNvRCMode; } GstNvRCMode;
typedef struct { typedef struct {
gboolean weighted_prediction; gboolean weighted_prediction;
gint rc_modes;
gboolean custom_vbv_bufsize;
gboolean lookahead;
gboolean temporal_aq;
} GstNvEncDeviceCaps; } GstNvEncDeviceCaps;
typedef struct { typedef struct {
@ -74,6 +81,15 @@ typedef struct {
gint qp_const; gint qp_const;
guint bitrate; guint bitrate;
gint gop_size; gint gop_size;
guint max_bitrate;
gboolean spatial_aq;
guint aq_strength;
gboolean non_refp;
/* zero reorder delay (consistent naming with x264) */
gboolean zerolatency;
gboolean strict_gop;
gdouble const_quality;
gboolean i_adapt;
GstCudaContext * cuda_ctx; GstCudaContext * cuda_ctx;
CUstream cuda_stream; CUstream cuda_stream;
@ -115,6 +131,9 @@ typedef struct {
/*< protected >*/ /*< protected >*/
/* device capability dependent properties, set by subclass */ /* device capability dependent properties, set by subclass */
gboolean weighted_pred; gboolean weighted_pred;
guint vbv_buffersize;
guint rc_lookahead;
gboolean temporal_aq;
} GstNvBaseEnc; } GstNvBaseEnc;
typedef struct { typedef struct {

View file

@ -681,15 +681,69 @@ gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec,
max_height = 4096; max_height = 4096;
} }
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",
i, 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; caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION;
if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, if (NvEncGetEncodeCaps (enc, codec_id, &caps_param,
&device_caps.weighted_prediction) != NV_ENC_SUCCESS) { &device_caps.weighted_prediction) != NV_ENC_SUCCESS) {
device_caps.weighted_prediction = FALSE; 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;
}
DEBUG_DEVICE_CAPS (i, DEBUG_DEVICE_CAPS (i,
codec, "weighted prediction", device_caps.weighted_prediction); codec, "weighted prediction", device_caps.weighted_prediction);
DEBUG_DEVICE_CAPS (i, codec, "custom vbv-buffer-size",
device_caps.custom_vbv_bufsize);
DEBUG_DEVICE_CAPS (i, codec, "rc-loockahead", device_caps.lookahead);
DEBUG_DEVICE_CAPS (i, codec, "temporal adaptive quantization",
device_caps.temporal_aq);
interlace_modes = gst_nvenc_get_interlace_modes (enc, codec_id); interlace_modes = gst_nvenc_get_interlace_modes (enc, codec_id);
sink_templ = gst_caps_new_empty_simple ("video/x-raw"); sink_templ = gst_caps_new_empty_simple ("video/x-raw");

View file

@ -44,10 +44,16 @@ enum
PROP_0, PROP_0,
PROP_AUD, PROP_AUD,
PROP_WEIGHTED_PRED, PROP_WEIGHTED_PRED,
PROP_VBV_BUFFER_SIZE,
PROP_RC_LOOKAHEAD,
PROP_TEMPORAL_AQ,
}; };
#define DEFAULT_AUD TRUE #define DEFAULT_AUD TRUE
#define DEFAULT_WEIGHTED_PRED FALSE #define DEFAULT_WEIGHTED_PRED FALSE
#define DEFAULT_VBV_BUFFER_SIZE 0
#define DEFAULT_RC_LOOKAHEAD 0
#define DEFAULT_TEMPORAL_AQ FALSE
static gboolean gst_nv_h264_enc_open (GstVideoEncoder * enc); static gboolean gst_nv_h264_enc_open (GstVideoEncoder * enc);
static gboolean gst_nv_h264_enc_close (GstVideoEncoder * enc); static gboolean gst_nv_h264_enc_close (GstVideoEncoder * enc);
@ -103,6 +109,36 @@ gst_nv_h264_enc_class_init (GstNvH264EncClass * klass, gpointer data)
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
} }
if (device_caps->custom_vbv_bufsize) {
g_object_class_install_property (gobject_class,
PROP_VBV_BUFFER_SIZE,
g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
"VBV(HRD) Buffer Size in kbits (0 = NVENC default) "
"(Exposed only if supported by device)", 0, G_MAXUINT,
DEFAULT_VBV_BUFFER_SIZE,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
}
if (device_caps->lookahead) {
g_object_class_install_property (gobject_class, PROP_RC_LOOKAHEAD,
g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead",
"Number of frames for frame type lookahead "
"(Exposed only if supported by device)", 0, 32,
DEFAULT_RC_LOOKAHEAD,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
}
if (device_caps->temporal_aq) {
g_object_class_install_property (gobject_class, PROP_TEMPORAL_AQ,
g_param_spec_boolean ("temporal-aq", "Temporal AQ",
"Temporal Adaptive Quantization "
"(Exposed only if supported by device)", DEFAULT_TEMPORAL_AQ,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
}
if (cdata->is_default) if (cdata->is_default)
long_name = g_strdup ("NVENC H.264 Video Encoder"); long_name = g_strdup ("NVENC H.264 Video Encoder");
else else
@ -141,6 +177,9 @@ gst_nv_h264_enc_init (GstNvH264Enc * nvenc)
/* device capability dependent properties */ /* device capability dependent properties */
baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED; baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED;
baseenc->vbv_buffersize = DEFAULT_VBV_BUFFER_SIZE;
baseenc->rc_lookahead = DEFAULT_RC_LOOKAHEAD;
baseenc->temporal_aq = DEFAULT_TEMPORAL_AQ;
} }
static void static void
@ -442,6 +481,30 @@ gst_nv_h264_enc_set_property (GObject * object, guint prop_id,
reconfig = TRUE; reconfig = TRUE;
} }
break; break;
case PROP_VBV_BUFFER_SIZE:
if (!device_caps->custom_vbv_bufsize) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
nvenc->vbv_buffersize = g_value_get_uint (value);
reconfig = TRUE;
}
break;
case PROP_RC_LOOKAHEAD:
if (!device_caps->lookahead) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
nvenc->rc_lookahead = g_value_get_uint (value);
reconfig = TRUE;
}
break;
case PROP_TEMPORAL_AQ:
if (!device_caps->temporal_aq) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
nvenc->temporal_aq = g_value_get_boolean (value);
reconfig = TRUE;
}
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -471,6 +534,27 @@ gst_nv_h264_enc_get_property (GObject * object, guint prop_id, GValue * value,
g_value_set_boolean (value, nvenc->weighted_pred); g_value_set_boolean (value, nvenc->weighted_pred);
} }
break; break;
case PROP_VBV_BUFFER_SIZE:
if (!device_caps->custom_vbv_bufsize) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
g_value_set_uint (value, nvenc->vbv_buffersize);
}
break;
case PROP_RC_LOOKAHEAD:
if (!device_caps->lookahead) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
g_value_set_uint (value, nvenc->rc_lookahead);
}
break;
case PROP_TEMPORAL_AQ:
if (!device_caps->temporal_aq) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
g_value_set_boolean (value, nvenc->temporal_aq);
}
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -46,10 +46,16 @@ enum
PROP_0, PROP_0,
PROP_AUD, PROP_AUD,
PROP_WEIGHTED_PRED, PROP_WEIGHTED_PRED,
PROP_VBV_BUFFER_SIZE,
PROP_RC_LOOKAHEAD,
PROP_TEMPORAL_AQ,
}; };
#define DEFAULT_AUD TRUE #define DEFAULT_AUD TRUE
#define DEFAULT_WEIGHTED_PRED FALSE #define DEFAULT_WEIGHTED_PRED FALSE
#define DEFAULT_VBV_BUFFER_SIZE 0
#define DEFAULT_RC_LOOKAHEAD 0
#define DEFAULT_TEMPORAL_AQ FALSE
static gboolean gst_nv_h265_enc_open (GstVideoEncoder * enc); static gboolean gst_nv_h265_enc_open (GstVideoEncoder * enc);
static gboolean gst_nv_h265_enc_close (GstVideoEncoder * enc); static gboolean gst_nv_h265_enc_close (GstVideoEncoder * enc);
@ -107,6 +113,36 @@ gst_nv_h265_enc_class_init (GstNvH265EncClass * klass, gpointer data)
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
} }
if (device_caps->custom_vbv_bufsize) {
g_object_class_install_property (gobject_class,
PROP_VBV_BUFFER_SIZE,
g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size",
"VBV(HRD) Buffer Size in kbits (0 = NVENC default) "
"(Exposed only if supported by device)", 0, G_MAXUINT,
DEFAULT_VBV_BUFFER_SIZE,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
}
if (device_caps->lookahead) {
g_object_class_install_property (gobject_class, PROP_RC_LOOKAHEAD,
g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead",
"Number of frames for frame type lookahead "
"(Exposed only if supported by device)", 0, 32,
DEFAULT_RC_LOOKAHEAD,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
}
if (device_caps->temporal_aq) {
g_object_class_install_property (gobject_class, PROP_TEMPORAL_AQ,
g_param_spec_boolean ("temporal-aq", "Temporal AQ",
"Temporal Adaptive Quantization "
"(Exposed only if supported by device)", DEFAULT_TEMPORAL_AQ,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS));
}
if (cdata->is_default) if (cdata->is_default)
long_name = g_strdup ("NVENC HEVC Video Encoder"); long_name = g_strdup ("NVENC HEVC Video Encoder");
else else
@ -145,6 +181,9 @@ gst_nv_h265_enc_init (GstNvH265Enc * nvenc)
/* device capability dependent properties */ /* device capability dependent properties */
baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED; baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED;
baseenc->vbv_buffersize = DEFAULT_VBV_BUFFER_SIZE;
baseenc->rc_lookahead = DEFAULT_RC_LOOKAHEAD;
baseenc->temporal_aq = DEFAULT_TEMPORAL_AQ;
} }
static void static void
@ -597,6 +636,30 @@ gst_nv_h265_enc_set_property (GObject * object, guint prop_id,
reconfig = TRUE; reconfig = TRUE;
} }
break; break;
case PROP_VBV_BUFFER_SIZE:
if (!device_caps->custom_vbv_bufsize) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
nvenc->vbv_buffersize = g_value_get_uint (value);
reconfig = TRUE;
}
break;
case PROP_RC_LOOKAHEAD:
if (!device_caps->lookahead) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
nvenc->rc_lookahead = g_value_get_uint (value);
reconfig = TRUE;
}
break;
case PROP_TEMPORAL_AQ:
if (!device_caps->temporal_aq) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
nvenc->temporal_aq = g_value_get_boolean (value);
reconfig = TRUE;
}
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -626,6 +689,27 @@ gst_nv_h265_enc_get_property (GObject * object, guint prop_id, GValue * value,
g_value_set_boolean (value, nvenc->weighted_pred); g_value_set_boolean (value, nvenc->weighted_pred);
} }
break; break;
case PROP_VBV_BUFFER_SIZE:
if (!device_caps->custom_vbv_bufsize) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
g_value_set_uint (value, nvenc->vbv_buffersize);
}
break;
case PROP_RC_LOOKAHEAD:
if (!device_caps->lookahead) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
g_value_set_uint (value, nvenc->rc_lookahead);
}
break;
case PROP_TEMPORAL_AQ:
if (!device_caps->temporal_aq) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} else {
g_value_set_boolean (value, nvenc->temporal_aq);
}
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;