From 05643dadb5c8c45e347a162c5cdc6f1c8d2d1cb8 Mon Sep 17 00:00:00 2001 From: He Junyan Date: Tue, 20 Aug 2019 22:16:35 +0800 Subject: [PATCH] gst: encode: add property help functions for encoder properties. The encoder is a true gstobject now and all the properties are using gobject's properties mechanism. Add help functions to handle the properties between encode and encoder class. The basic idea is mapping the same property between encoder and encode. All the encoder's properties will have the same name, the same type in encode. The set/get property function just forward the property setting/getting to the encoder using the same property name and value. Because the encoder is created on needed, we need to cache the property setting in encode. --- gst/vaapi/gstvaapiencode.c | 197 ++++++++++++++++++++++++++++++++++++- gst/vaapi/gstvaapiencode.h | 17 +++- 2 files changed, 212 insertions(+), 2 deletions(-) diff --git a/gst/vaapi/gstvaapiencode.c b/gst/vaapi/gstvaapiencode.c index 6ca10e3398..975fe49f30 100644 --- a/gst/vaapi/gstvaapiencode.c +++ b/gst/vaapi/gstvaapiencode.c @@ -104,7 +104,7 @@ gst_vaapiencode_src_query (GstVideoEncoder * encoder, GstQuery * query) typedef struct { - GstVaapiEncoderProp id; + guint id; GParamSpec *pspec; GValue value; } PropValue; @@ -158,6 +158,47 @@ prop_value_lookup (GstVaapiEncode * encode, guint prop_id) return NULL; } +static PropValue * +prop_value_new_entry (guint id, GParamSpec * pspec, const GValue * value) +{ + PropValue *prop_value; + + if (!pspec) + return NULL; + + prop_value = g_slice_new0 (PropValue); + if (!prop_value) + return NULL; + + prop_value->id = id; + prop_value->pspec = g_param_spec_ref (pspec); + g_value_init (&prop_value->value, pspec->value_type); + + g_assert (g_value_type_compatible (pspec->value_type, G_VALUE_TYPE (value))); + g_value_copy (value, &prop_value->value); + + return prop_value; +} + +static inline PropValue * +prop_value_lookup_entry (GPtrArray * prop_values, guint prop_id) +{ + guint i; + PropValue *prop_value; + + if (prop_values == NULL) + return NULL; + + for (i = 0; i < prop_values->len; i++) { + prop_value = g_ptr_array_index (prop_values, i); + if (prop_value->id == prop_id) + return prop_value; + } + + return NULL; +} + + static gboolean gst_vaapiencode_default_get_property (GstVaapiEncode * encode, guint prop_id, GValue * value) @@ -1007,3 +1048,157 @@ gst_vaapiencode_class_init_properties (GstVaapiEncodeClass * klass) g_ptr_array_unref (props); return TRUE; } + +/* Only used by the drived class */ +void +gst_vaapiencode_set_property_subclass (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object); + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object); + PropValue *prop_value; + + if (prop_id <= PROP_BASE || prop_id >= encode_class->prop_num) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + /* direct forward the property to encoder */ + if (encode->encoder) { + g_object_set_property ((GObject *) encode->encoder, + g_param_spec_get_name (pspec), value); + return; + } + + if (encode->prop_values) { + /* Delete the same prop already in cache */ + prop_value = prop_value_lookup_entry (encode->prop_values, prop_id); + if (prop_value) + g_ptr_array_remove (encode->prop_values, prop_value); + } else { + encode->prop_values = + g_ptr_array_new_with_free_func ((GDestroyNotify) prop_value_free); + } + + /* The encoder is delay created, we need to cache the property setting */ + prop_value = prop_value_new_entry (prop_id, pspec, value); + g_ptr_array_add (encode->prop_values, prop_value); +} + +/* Only used by the drived class */ +void +gst_vaapiencode_get_property_subclass (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object); + GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object); + PropValue *prop_value = NULL; + + if (prop_id <= PROP_BASE || prop_id >= encode_class->prop_num) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + return; + } + + /* direct forward the property to encoder */ + if (encode->encoder) { + g_object_get_property ((GObject *) encode->encoder, + g_param_spec_get_name (pspec), value); + return; + } + + if (encode->prop_values) + prop_value = prop_value_lookup_entry (encode->prop_values, prop_id); + + if (prop_value) { + /* In the cache */ + g_value_copy (&prop_value->value, value); + } else { + /* set the default value */ + g_param_value_set_default (pspec, value); + } +} + +/* Called by drived class to install all properties. The encode base class + does not have any property, all the properties of the according encoderXXX + class are installed to encodeXXX class. */ +gboolean +gst_vaapiencode_class_install_properties (GstVaapiEncodeClass * klass, + GObjectClass * encoder_class) +{ + GObjectClass *const object_class = G_OBJECT_CLASS (klass); + guint i, n_props, installed; + GParamSpec **specs = NULL; + GParamSpec *pspec; + GParamSpec *new_spec; + GParamFlags flags; + + if (encoder_class) + specs = g_object_class_list_properties (encoder_class, &n_props); + if (!specs) + return FALSE; + + installed = 0; + for (i = 0; i < n_props; i++) { + pspec = specs[i]; + + /* Encoder do not want to expose */ + if (!(pspec->flags & G_PARAM_FLAG_VAAPI_ENCODER_EXPOSURE)) + continue; + /* Can only set on encoder init time */ + if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) + continue; + + /* filter out the G_PARAM_CONSTRUCT, the encoder created later, no need + to set the init value in encode. + Also no G_PARAM_FLAG_VAAPI_ENCODER_EXPOSURE */ + flags = pspec->flags & (~(G_PARAM_FLAG_VAAPI_ENCODER_EXPOSURE | + G_PARAM_CONSTRUCT)); + + if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_UINT) { + GParamSpecUInt *pspecuint = G_PARAM_SPEC_UINT (pspec); + new_spec = g_param_spec_uint (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecuint->minimum, pspecuint->maximum, + pspecuint->default_value, flags); + } else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT) { + GParamSpecInt *pspecint = G_PARAM_SPEC_INT (pspec); + new_spec = g_param_spec_int (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecint->minimum, pspecint->maximum, pspecint->default_value, flags); + } else if (G_IS_PARAM_SPEC_ENUM (pspec)) { + GParamSpecEnum *pspecenum = G_PARAM_SPEC_ENUM (pspec); + new_spec = g_param_spec_enum (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), + g_param_spec_get_blurb (pspec), + pspec->value_type, pspecenum->default_value, flags); + } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) { + GParamSpecBoolean *pspecbool = G_PARAM_SPEC_BOOLEAN (pspec); + new_spec = g_param_spec_boolean (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecbool->default_value, flags); + } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) { + GParamSpecFlags *pspecflags = G_PARAM_SPEC_FLAGS (pspec); + new_spec = g_param_spec_flags (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspec->value_type, pspecflags->default_value, flags); + } else if (GST_IS_PARAM_SPEC_ARRAY_LIST (pspec)) { + GstParamSpecArray *pspecarray = GST_PARAM_SPEC_ARRAY_LIST (pspec); + new_spec = gst_param_spec_array (g_param_spec_get_name (pspec), + g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec), + pspecarray->element_spec, flags); + } else { + GST_WARNING ("encoder's %s property has a unimplemented" + " type to expose to encode, the encode may lose the %s property", + g_param_spec_get_name (pspec), g_param_spec_get_name (pspec)); + continue; + } + + g_object_class_install_property (object_class, PROP_BASE + 1 + installed, + new_spec); + installed++; + } + + g_free (specs); + klass->prop_num = PROP_BASE + 1 + installed; + return TRUE; +} diff --git a/gst/vaapi/gstvaapiencode.h b/gst/vaapi/gstvaapiencode.h index b63828526c..742de05f7c 100644 --- a/gst/vaapi/gstvaapiencode.h +++ b/gst/vaapi/gstvaapiencode.h @@ -73,6 +73,7 @@ struct _GstVaapiEncodeClass /*< private >*/ GstVaapiPluginBaseClass parent_class; + guint prop_num; GPtrArray * (*get_properties) (void); gboolean (*get_property) (GstVaapiEncode * encode, guint prop_id, GValue * value); @@ -98,7 +99,6 @@ struct _GstVaapiEncodeClass GstVaapiCodedBufferProxy *proxy); #endif - }; GType @@ -112,6 +112,21 @@ G_GNUC_INTERNAL gboolean gst_vaapiencode_class_init_properties (GstVaapiEncodeClass * encode_class); +G_GNUC_INTERNAL +void +gst_vaapiencode_set_property_subclass (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); + +G_GNUC_INTERNAL +void +gst_vaapiencode_get_property_subclass (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +G_GNUC_INTERNAL +gboolean +gst_vaapiencode_class_install_properties (GstVaapiEncodeClass * klass, + GObjectClass * encoder_class); + G_END_DECLS #endif /* GST_VAAPIENCODE_H */