From ea19a7c71585262c70c7f3922611093b1f46f208 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Tue, 3 Sep 2019 21:28:44 +0900 Subject: [PATCH] nvenc: Add support for weighted prediction option Note that this property will be exposed only if the device supports the weighted prediction. --- sys/nvcodec/gstnvbaseenc.c | 25 +++++++++++++++++++---- sys/nvcodec/gstnvbaseenc.h | 12 ++++++++++- sys/nvcodec/gstnvenc.c | 20 ++++++++++++++++-- sys/nvcodec/gstnvh264enc.c | 42 ++++++++++++++++++++++++++++++++++++-- sys/nvcodec/gstnvh264enc.h | 3 ++- sys/nvcodec/gstnvh265enc.c | 42 ++++++++++++++++++++++++++++++++++++-- sys/nvcodec/gstnvh265enc.h | 3 ++- 7 files changed, 134 insertions(+), 13 deletions(-) diff --git a/sys/nvcodec/gstnvbaseenc.c b/sys/nvcodec/gstnvbaseenc.c index f203e0d90d..56b4eaffb0 100644 --- a/sys/nvcodec/gstnvbaseenc.c +++ b/sys/nvcodec/gstnvbaseenc.c @@ -1311,6 +1311,8 @@ gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state) } } + params->enableWeightedPrediction = nvenc->weighted_pred; + if (nvenc->gop_size < 0) { params->encodeConfig->gopLength = NVENC_INFINITE_GOPLENGTH; params->encodeConfig->frameIntervalP = 1; @@ -2243,22 +2245,33 @@ gst_nv_base_enc_get_property (GObject * object, guint prop_id, GValue * value, } } +typedef struct +{ + guint cuda_device_id; + GstNvEncDeviceCaps device_caps; +} GstNvEncClassData; + static void gst_nv_base_enc_subclass_init (gpointer g_class, gpointer data) { GstNvBaseEncClass *nvbaseenc_class = GST_NV_BASE_ENC_CLASS (g_class); - guint device_id = GPOINTER_TO_UINT (data); + GstNvEncClassData *cdata = (GstNvEncClassData *) data; - nvbaseenc_class->cuda_device_id = device_id; + nvbaseenc_class->cuda_device_id = cdata->cuda_device_id; + nvbaseenc_class->device_caps = cdata->device_caps; + + g_free (cdata); } GType -gst_nv_base_enc_register (const char *codec, guint device_id) +gst_nv_base_enc_register (const char *codec, guint device_id, + GstNvEncDeviceCaps * device_caps) { GTypeQuery type_query; GTypeInfo type_info = { 0, }; GType subtype; gchar *type_name; + GstNvEncClassData *cdata; type_name = g_strdup_printf ("GstNvDevice%d%sEnc", device_id, codec); subtype = g_type_from_name (type_name); @@ -2267,12 +2280,16 @@ gst_nv_base_enc_register (const char *codec, guint device_id) if (subtype) goto done; + cdata = g_new0 (GstNvEncClassData, 1); + cdata->cuda_device_id = device_id; + cdata->device_caps = *device_caps; + g_type_query (GST_TYPE_NV_BASE_ENC, &type_query); memset (&type_info, 0, sizeof (type_info)); type_info.class_size = type_query.class_size; type_info.instance_size = type_query.instance_size; type_info.class_init = (GClassInitFunc) gst_nv_base_enc_subclass_init; - type_info.class_data = GUINT_TO_POINTER (device_id); + type_info.class_data = cdata; subtype = g_type_register_static (GST_TYPE_NV_BASE_ENC, type_name, &type_info, 0); diff --git a/sys/nvcodec/gstnvbaseenc.h b/sys/nvcodec/gstnvbaseenc.h index 1e9d36551c..bf3ed23029 100644 --- a/sys/nvcodec/gstnvbaseenc.h +++ b/sys/nvcodec/gstnvbaseenc.h @@ -58,6 +58,10 @@ typedef enum { GST_NV_RC_MODE_VBR_MINQP, } GstNvRCMode; +typedef struct { + gboolean weighted_prediction; +} GstNvEncDeviceCaps; + typedef struct { GstVideoEncoder video_encoder; @@ -107,6 +111,10 @@ typedef struct { GstVideoInfo input_info; /* buffer configuration for buffers sent to NVENC */ GstFlowReturn last_flow; /* ATOMIC */ + + /*< protected >*/ + /* device capability dependent properties, set by subclass */ + gboolean weighted_pred; } GstNvBaseEnc; typedef struct { @@ -114,6 +122,7 @@ typedef struct { GUID codec_id; guint cuda_device_id; + GstNvEncDeviceCaps device_caps; gboolean (*set_src_caps) (GstNvBaseEnc * nvenc, GstVideoCodecState * state); @@ -129,7 +138,8 @@ G_GNUC_INTERNAL GType gst_nv_base_enc_get_type (void); GType gst_nv_base_enc_register (const char * codec, - guint device_id); + guint device_id, + GstNvEncDeviceCaps * device_caps); void gst_nv_base_enc_schedule_reconfig (GstNvBaseEnc * nvenc); diff --git a/sys/nvcodec/gstnvenc.c b/sys/nvcodec/gstnvenc.c index 49cff2e03c..e492cba98c 100644 --- a/sys/nvcodec/gstnvenc.c +++ b/sys/nvcodec/gstnvenc.c @@ -592,6 +592,10 @@ gst_nvenc_get_supported_codec_profiles (gpointer enc, GUID codec_id) return ret; } +#define DEBUG_DEVICE_CAPS(d,c,caps,s) \ + GST_DEBUG ("[device-%d %s] %s: %s", \ + d, c, caps, s ? "supported" : "not supported"); + static void gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec, guint rank, gint device_count) @@ -615,6 +619,7 @@ gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec, GstCaps *src_templ = NULL; gchar *name; gint j; + GstNvEncDeviceCaps device_caps = { 0, }; if (CuDeviceGet (&cuda_device, i) != CUDA_SUCCESS) continue; @@ -676,6 +681,15 @@ gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec, max_height = 4096; } + 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; + } + + DEBUG_DEVICE_CAPS (i, + codec, "weighted prediction", device_caps.weighted_prediction); + interlace_modes = gst_nvenc_get_interlace_modes (enc, codec_id); sink_templ = gst_caps_new_empty_simple ("video/x-raw"); @@ -732,9 +746,11 @@ gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec, if (sink_templ && src_templ) { if (gst_nvenc_cmp_guid (codec_id, NV_ENC_CODEC_H264_GUID)) { - gst_nv_h264_enc_register (plugin, i, rank, sink_templ, src_templ); + gst_nv_h264_enc_register (plugin, i, 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, i, rank, sink_templ, src_templ); + gst_nv_h265_enc_register (plugin, i, rank, sink_templ, src_templ, + &device_caps); } else { g_assert_not_reached (); } diff --git a/sys/nvcodec/gstnvh264enc.c b/sys/nvcodec/gstnvh264enc.c index b63442b5bd..6ef3c005fb 100644 --- a/sys/nvcodec/gstnvh264enc.c +++ b/sys/nvcodec/gstnvh264enc.c @@ -43,9 +43,11 @@ enum { PROP_0, PROP_AUD, + PROP_WEIGHTED_PRED, }; #define DEFAULT_AUD TRUE +#define DEFAULT_WEIGHTED_PRED FALSE static gboolean gst_nv_h264_enc_open (GstVideoEncoder * enc); static gboolean gst_nv_h264_enc_close (GstVideoEncoder * enc); @@ -68,6 +70,7 @@ gst_nv_h264_enc_class_init (GstNvH264EncClass * klass, gpointer data) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass); GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_CLASS (klass); + GstNvEncDeviceCaps *device_caps = &nvenc_class->device_caps; GstNvH264EncClassData *cdata = (GstNvH264EncClassData *) data; gchar *long_name; @@ -91,6 +94,15 @@ gst_nv_h264_enc_class_init (GstNvH264EncClass * klass, gpointer data) G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS)); + if (device_caps->weighted_prediction) { + g_object_class_install_property (gobject_class, PROP_WEIGHTED_PRED, + g_param_spec_boolean ("weighted-pred", "Weighted Pred", + "Weighted Prediction " + "(Exposed only if supported by device)", DEFAULT_WEIGHTED_PRED, + G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | + G_PARAM_STATIC_STRINGS)); + } + if (cdata->is_default) long_name = g_strdup ("NVENC H.264 Video Encoder"); else @@ -123,7 +135,12 @@ gst_nv_h264_enc_class_init (GstNvH264EncClass * klass, gpointer data) static void gst_nv_h264_enc_init (GstNvH264Enc * nvenc) { + GstNvBaseEnc *baseenc = GST_NV_BASE_ENC (nvenc); + nvenc->aud = DEFAULT_AUD; + + /* device capability dependent properties */ + baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED; } static void @@ -400,6 +417,9 @@ gst_nv_h264_enc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstNvH264Enc *self = (GstNvH264Enc *) object; + GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); + GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); + GstNvEncDeviceCaps *device_caps = &klass->device_caps; gboolean reconfig = FALSE; switch (prop_id) { @@ -414,6 +434,14 @@ gst_nv_h264_enc_set_property (GObject * object, guint prop_id, } break; } + case PROP_WEIGHTED_PRED: + if (!device_caps->weighted_prediction) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } else { + nvenc->weighted_pred = g_value_get_boolean (value); + reconfig = TRUE; + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -428,11 +456,21 @@ gst_nv_h264_enc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstNvH264Enc *self = (GstNvH264Enc *) object; + GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); + GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); + GstNvEncDeviceCaps *device_caps = &klass->device_caps; switch (prop_id) { case PROP_AUD: g_value_set_boolean (value, self->aud); break; + case PROP_WEIGHTED_PRED: + if (!device_caps->weighted_prediction) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } else { + g_value_set_boolean (value, nvenc->weighted_pred); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -441,7 +479,7 @@ gst_nv_h264_enc_get_property (GObject * object, guint prop_id, GValue * value, void gst_nv_h264_enc_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) + GstCaps * sink_caps, GstCaps * src_caps, GstNvEncDeviceCaps * device_caps) { GType parent_type; GType type; @@ -461,7 +499,7 @@ gst_nv_h264_enc_register (GstPlugin * plugin, guint device_id, guint rank, (GInstanceInitFunc) gst_nv_h264_enc_init, }; - parent_type = gst_nv_base_enc_register ("H264", device_id); + parent_type = gst_nv_base_enc_register ("H264", device_id, device_caps); cdata = g_new0 (GstNvH264EncClassData, 1); cdata->sink_caps = gst_caps_ref (sink_caps); diff --git a/sys/nvcodec/gstnvh264enc.h b/sys/nvcodec/gstnvh264enc.h index a6ab4e4a1c..31b4d501d2 100644 --- a/sys/nvcodec/gstnvh264enc.h +++ b/sys/nvcodec/gstnvh264enc.h @@ -37,7 +37,8 @@ void gst_nv_h264_enc_register (GstPlugin * plugin, guint device_id, guint rank, GstCaps * sink_caps, - GstCaps * src_caps); + GstCaps * src_caps, + GstNvEncDeviceCaps * device_caps); #endif /* __GST_NV_H264_ENC_H_INCLUDED__ */ diff --git a/sys/nvcodec/gstnvh265enc.c b/sys/nvcodec/gstnvh265enc.c index fc4a506fb5..f388541a54 100644 --- a/sys/nvcodec/gstnvh265enc.c +++ b/sys/nvcodec/gstnvh265enc.c @@ -45,9 +45,11 @@ enum { PROP_0, PROP_AUD, + PROP_WEIGHTED_PRED, }; #define DEFAULT_AUD TRUE +#define DEFAULT_WEIGHTED_PRED FALSE static gboolean gst_nv_h265_enc_open (GstVideoEncoder * enc); static gboolean gst_nv_h265_enc_close (GstVideoEncoder * enc); @@ -71,6 +73,7 @@ gst_nv_h265_enc_class_init (GstNvH265EncClass * klass, gpointer data) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass); GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_CLASS (klass); + GstNvEncDeviceCaps *device_caps = &nvenc_class->device_caps; GstNvH265EncClassData *cdata = (GstNvH265EncClassData *) data; gchar *long_name; @@ -95,6 +98,15 @@ gst_nv_h265_enc_class_init (GstNvH265EncClass * klass, gpointer data) G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS)); + if (device_caps->weighted_prediction) { + g_object_class_install_property (gobject_class, PROP_WEIGHTED_PRED, + g_param_spec_boolean ("weighted-pred", "Weighted Pred", + "Weighted Prediction " + "(Exposed only if supported by device)", DEFAULT_WEIGHTED_PRED, + G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | + G_PARAM_STATIC_STRINGS)); + } + if (cdata->is_default) long_name = g_strdup ("NVENC HEVC Video Encoder"); else @@ -127,7 +139,12 @@ gst_nv_h265_enc_class_init (GstNvH265EncClass * klass, gpointer data) static void gst_nv_h265_enc_init (GstNvH265Enc * nvenc) { + GstNvBaseEnc *baseenc = GST_NV_BASE_ENC (nvenc); + nvenc->aud = DEFAULT_AUD; + + /* device capability dependent properties */ + baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED; } static void @@ -555,6 +572,9 @@ gst_nv_h265_enc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstNvH265Enc *self = (GstNvH265Enc *) object; + GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); + GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); + GstNvEncDeviceCaps *device_caps = &klass->device_caps; gboolean reconfig = FALSE; switch (prop_id) { @@ -569,6 +589,14 @@ gst_nv_h265_enc_set_property (GObject * object, guint prop_id, } break; } + case PROP_WEIGHTED_PRED: + if (!device_caps->weighted_prediction) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } else { + nvenc->weighted_pred = g_value_get_boolean (value); + reconfig = TRUE; + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -583,11 +611,21 @@ gst_nv_h265_enc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstNvH265Enc *self = (GstNvH265Enc *) object; + GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); + GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); + GstNvEncDeviceCaps *device_caps = &klass->device_caps; switch (prop_id) { case PROP_AUD: g_value_set_boolean (value, self->aud); break; + case PROP_WEIGHTED_PRED: + if (!device_caps->weighted_prediction) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } else { + g_value_set_boolean (value, nvenc->weighted_pred); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -596,7 +634,7 @@ gst_nv_h265_enc_get_property (GObject * object, guint prop_id, GValue * value, void gst_nv_h265_enc_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) + GstCaps * sink_caps, GstCaps * src_caps, GstNvEncDeviceCaps * device_caps) { GType parent_type; GType type; @@ -616,7 +654,7 @@ gst_nv_h265_enc_register (GstPlugin * plugin, guint device_id, guint rank, (GInstanceInitFunc) gst_nv_h265_enc_init, }; - parent_type = gst_nv_base_enc_register ("H265", device_id); + parent_type = gst_nv_base_enc_register ("H265", device_id, device_caps); cdata = g_new0 (GstNvH265EncClassData, 1); cdata->sink_caps = gst_caps_ref (sink_caps); diff --git a/sys/nvcodec/gstnvh265enc.h b/sys/nvcodec/gstnvh265enc.h index 22daa3f87a..80226a60ab 100644 --- a/sys/nvcodec/gstnvh265enc.h +++ b/sys/nvcodec/gstnvh265enc.h @@ -42,6 +42,7 @@ void gst_nv_h265_enc_register (GstPlugin * plugin, guint device_id, guint rank, GstCaps * sink_caps, - GstCaps * src_caps); + GstCaps * src_caps, + GstNvEncDeviceCaps * device_caps); #endif /* __GST_NV_HEVC_ENC_H_INCLUDED__ */