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.
This commit is contained in:
He Junyan 2019-08-20 22:16:35 +08:00
parent bc2f8fd19e
commit 05643dadb5
2 changed files with 212 additions and 2 deletions

View file

@ -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;
}

View file

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