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 */