gst: encode: add property help functions for encoder properties.
authorHe Junyan <junyan.he@hotmail.com>
Tue, 20 Aug 2019 14:16:35 +0000 (22:16 +0800)
committerHe Junyan <junyan.he@hotmail.com>
Fri, 30 Aug 2019 13:06:47 +0000 (21:06 +0800)
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
gst/vaapi/gstvaapiencode.h

index 6ca10e3..975fe49 100644 (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;
+}
index b638285..742de05 100644 (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 */