Index: gst-plugins/configure.ac
--- gst-plugins~profiles/configure.ac	2004-03-25 22:53:34.000000000 +0100
+++ gst-plugins/configure.ac	2004-03-28 18:44:07.000000000 +0200
@@ -1720,6 +1720,7 @@
 gst-libs/gst/mixer/Makefile
 gst-libs/gst/navigation/Makefile
 gst-libs/gst/play/Makefile
+gst-libs/gst/profiles/Makefile
 gst-libs/gst/propertyprobe/Makefile
 gst-libs/gst/resample/Makefile
 gst-libs/gst/riff/Makefile
@@ -1755,6 +1756,8 @@
 pkgconfig/gstreamer-play-uninstalled.pc
 pkgconfig/gstreamer-plugins.pc
 pkgconfig/gstreamer-plugins-uninstalled.pc
+pkgconfig/gstreamer-profiles.pc
+pkgconfig/gstreamer-profiles-uninstalled.pc
 po/Makefile.in
 common/Makefile
 common/m4/Makefile
Index: gst-plugins/ext/mpeg2enc/gstmpeg2enc.cc
--- gst-plugins~profiles/ext/mpeg2enc/gstmpeg2enc.cc	2004-03-23 21:33:09.000000000 +0100
+++ gst-plugins/ext/mpeg2enc/gstmpeg2enc.cc	2004-03-25 22:53:35.000000000 +0100
@@ -23,6 +23,8 @@
 #include "config.h"
 #endif
 
+#include <gst/profiles/profilemanager.h>
+
 #include "gstmpeg2enc.hh"
 
 /*
@@ -97,6 +99,7 @@
 
 static void gst_mpeg2enc_base_init (GstMpeg2encClass * klass);
 static void gst_mpeg2enc_class_init (GstMpeg2encClass * klass);
+static void gst_mpeg2enc_profile_init (GstProfileManagerInterface * iface);
 static void gst_mpeg2enc_init (GstMpeg2enc * enc);
 static void gst_mpeg2enc_dispose (GObject * object);
 
@@ -131,10 +134,18 @@
       0,
       (GInstanceInitFunc) gst_mpeg2enc_init,
     };
-
+    static const GInterfaceInfo gst_mpeg2enc_profile_info = {
+      (GInterfaceInitFunc) gst_mpeg2enc_profile_init,
+      NULL,
+      NULL,
+    };
+                                                                                
     gst_mpeg2enc_type =
         g_type_register_static (GST_TYPE_ELEMENT,
         "GstMpeg2enc", &gst_mpeg2enc_info, (GTypeFlags) 0);
+
+    g_type_add_interface_static (gst_mpeg2enc_type,
+	GST_TYPE_PROFILE_MANAGER, &gst_mpeg2enc_profile_info);
   }
 
   return gst_mpeg2enc_type;
@@ -190,6 +201,18 @@
   delete enc->options;
 }
 
+static const GList *
+gst_mpeg2enc_profile_get_list (GstElementClass *klass)
+{
+  return GstMpeg2EncOptions::initProfiles (G_OBJECT_CLASS (klass));
+}
+
+static void
+gst_mpeg2enc_profile_init (GstProfileManagerInterface *iface)
+{
+  iface->get_default_profiles = gst_mpeg2enc_profile_get_list;
+}
+
 static void
 gst_mpeg2enc_init (GstMpeg2enc * enc)
 {
Index: gst-plugins/ext/mpeg2enc/gstmpeg2encoptions.cc
--- gst-plugins~profiles/ext/mpeg2enc/gstmpeg2encoptions.cc	2004-03-23 21:33:09.000000000 +0100
+++ gst-plugins/ext/mpeg2enc/gstmpeg2encoptions.cc	2004-03-25 22:53:35.000000000 +0100
@@ -23,6 +23,8 @@
 #include "config.h"
 #endif
 
+#include <gst/profiles/profile.h>
+
 #include "gstmpeg2encoptions.hh"
 
 /*
@@ -75,6 +77,20 @@
 #define GST_TYPE_MPEG2ENC_FORMAT \
   (gst_mpeg2enc_format_get_type ())
 
+static const gchar *format_descriptions[] = {
+  "Generic MPEG-1",
+  "Standard VCD",
+  "User VCD",
+  "Generic MPEG-2",
+  "Standard SVCD",
+  "User SVCD",
+  "VCD Stills sequences",
+  "SVCD Stills sequences",
+  "DVD MPEG-2 for dvdauthor",
+  "DVD MPEG-2",
+  NULL
+};
+
 static GType
 gst_mpeg2enc_format_get_type (void)
 {
@@ -445,6 +461,44 @@
 }
 
 /*
+ * Profile interface.
+ */
+
+const GList *
+GstMpeg2EncOptions::initProfiles (GObjectClass *object_klass)
+{
+  static GList *items = NULL;
+
+  if (!items) {
+    GParamSpec *pspec = g_object_class_find_property (object_klass, "format");
+    GEnumClass *klass = G_ENUM_CLASS (g_type_class_peek (GST_TYPE_MPEG2ENC_FORMAT));
+    guint i;
+
+    g_assert (pspec);
+
+    for (i = 0; i < klass->n_values;i++) {
+      GEnumValue *value = g_enum_get_value (klass, i);
+      GstProfile *profile;
+      GstProfileParameter *param;
+      GList *params = NULL;
+
+      /* make parameters */
+      param = g_new0 (GstProfileParameter, 1);
+      param->pspec = pspec;
+      g_value_init (&param->value, GST_TYPE_MPEG2ENC_FORMAT);
+      g_value_set_enum (&param->value, i);
+      params = g_list_append (params, param);
+
+      profile = gst_profile_create (value->value_nick,
+				    format_descriptions[i], params);
+      items = g_list_append (items, profile);
+    }
+  }
+
+  return items;
+}
+
+/*
  * GObject property foo, C++ style.
  */
 
Index: gst-plugins/ext/mpeg2enc/gstmpeg2encoptions.hh
--- gst-plugins~profiles/ext/mpeg2enc/gstmpeg2encoptions.hh	2004-03-23 21:33:09.000000000 +0100
+++ gst-plugins/ext/mpeg2enc/gstmpeg2encoptions.hh	2004-03-25 22:53:35.000000000 +0100
@@ -32,6 +32,9 @@
   /* Init properties (call once) */
   static void initProperties (GObjectClass *klass);
 
+  /* profile interface */
+  static const GList *initProfiles (GObjectClass *klass);
+
   /* GObject property foo, C++ style */
   void getProperty (guint         prop_id,
 		    GValue       *value);
Index: gst-plugins/ext/mpeg2enc/Makefile.am
--- gst-plugins~profiles/ext/mpeg2enc/Makefile.am	2004-03-23 21:33:09.000000000 +0100
+++ gst-plugins/ext/mpeg2enc/Makefile.am	2004-03-25 22:53:35.000000000 +0100
@@ -7,7 +7,8 @@
 	gstmpeg2encstreamwriter.cc \
 	gstmpeg2encpicturereader.cc
 libgstmpeg2enc_la_CXXFLAGS = $(MPEG2ENC_CFLAGS) $(GST_CFLAGS)
-libgstmpeg2enc_la_LIBADD = $(MPEG2ENC_LIBS) $(GST_PLUGIN_LDFLAGS)
+libgstmpeg2enc_la_LIBADD = $(top_builddir)/gst-libs/gst/profiles/libgstprofiles.la
+libgstmpeg2enc_la_LDFLAGS = $(MPEG2ENC_LIBS) $(GST_PLUGIN_LDFLAGS)
 
 noinst_HEADERS = \
 	gstmpeg2enc.hh \
Index: gst-plugins/gst-libs/gst/Makefile.am
--- gst-plugins~profiles/gst-libs/gst/Makefile.am	2004-03-23 21:33:09.000000000 +0100
+++ gst-plugins/gst-libs/gst/Makefile.am	2004-03-25 22:53:35.000000000 +0100
@@ -20,6 +20,7 @@
 	mixer \
 	navigation \
 	play \
+	profiles \
 	propertyprobe \
 	resample \
 	riff \
@@ -39,6 +40,7 @@
 	mixer \
 	navigation \
 	play \
+	profiles \
 	propertyprobe \
 	resample \
 	riff \
Index: gst-plugins/gst-libs/gst/profiles/Makefile.am
--- gst-plugins~profiles/gst-libs/gst/profiles/Makefile.am	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/Makefile.am	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,47 @@
+lib_LTLIBRARIES = libgstprofiles.la
+
+libgstprofiles_la_SOURCES = \
+	profile.c \
+	profilemanager.c \
+	profilesmarshal.c \
+	profilexml.c
+
+libgstprofilesincludedir = \
+	$(includedir)/gstreamer-@GST_MAJORMINOR@/gst/profiles
+
+libgstprofilesinclude_HEADERS = \
+	profile.h \
+	profilemanager.h \
+	profilesmarshal.h \
+	profilexml.h
+
+libgstprofiles_la_CFLAGS = $(GST_CFLAGS)
+
+BUILT_SOURCES = \
+	profilesmarshal.c \
+	profilesmarshal.h
+built_headers =	\
+	profilesmarshal.h
+
+EXTRA_DIST = profilesmarshal.list
+
+CLEANFILES = $(BUILT_SOURCES)
+
+profilesmarshal.h: profilesmarshal.list
+	glib-genmarshal --header --prefix=gst_profiles_marshal $^ > profilesmarshal.h.tmp
+	mv profilesmarshal.h.tmp profilesmarshal.h
+
+profilesmarshal.c: profilesmarshal.list
+	echo "#include \"profilesmarshal.h\"" >> profilesmarshal.c.tmp
+	glib-genmarshal --body --prefix=gst_profiles_marshal $^ >> profilesmarshal.c.tmp
+	mv profilesmarshal.c.tmp profilesmarshal.c
+
+noinst_PROGRAMS = \
+	showprofile
+showprofile_SOURCES = \
+	showprofile.c
+showprofile_CFLAGS = \
+	$(GST_CFLAGS)
+showprofile_LDFLAGS = \
+	$(GST_LIBS) \
+	libgstprofiles.la
Index: gst-plugins/gst-libs/gst/profiles/profile.c
--- gst-plugins~profiles/gst-libs/gst/profiles/profile.c	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profile.c	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,406 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * profile.c: object code for handling a single profile
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "profilesmarshal.h"
+#include "profile.h"
+
+/* signals */
+enum {
+  SIGNAL_PROPERTY_ADDED,
+  SIGNAL_PROPERTY_REMOVED,
+  SIGNAL_PROPERTY_CHANGED,
+  SIGNAL_LABEL_CHANGED,
+  SIGNAL_DESCRIPTION_CHANGED,
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+static void	gst_profile_class_init (GstProfileClass *klass);
+static void	gst_profile_init       (GstProfile      *profile);
+static void	gst_profile_dispose    (GObject         *object);
+
+static GObjectClass *parent_class = NULL;
+static guint gst_profile_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_profile_get_type (void)
+{
+  static GType gst_profile_type = 0;
+
+  if (!gst_profile_type) {
+    static const GTypeInfo profile_info = {
+      sizeof (GstProfileClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) gst_profile_class_init,
+      NULL,
+      NULL,
+      sizeof (GstProfile),
+      0,
+      (GInstanceInitFunc) gst_profile_init,
+      NULL
+    };
+
+    gst_profile_type =
+	g_type_register_static (G_TYPE_OBJECT,
+				"GstProfile",
+				&profile_info, 0);
+  }
+
+  return gst_profile_type;
+}
+
+static void
+gst_profile_class_init (GstProfileClass *klass)
+{
+  GObjectClass *object_klass = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+  gst_profile_signals[SIGNAL_PROPERTY_ADDED] =
+    g_signal_new ("property_added", G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GstProfileClass, property_added),
+                  NULL, NULL, gst_profiles_marshal_VOID__POINTER_POINTER,
+                  G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+  gst_profile_signals[SIGNAL_PROPERTY_REMOVED] =
+    g_signal_new ("property_removed", G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GstProfileClass, property_removed),
+                  NULL, NULL, gst_profiles_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1, G_TYPE_POINTER);
+  gst_profile_signals[SIGNAL_PROPERTY_CHANGED] =
+    g_signal_new ("property_changed", G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GstProfileClass, property_changed),
+                  NULL, NULL, gst_profiles_marshal_VOID__POINTER_POINTER,
+                  G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+  gst_profile_signals[SIGNAL_LABEL_CHANGED] =
+    g_signal_new ("label_changed", G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GstProfileClass, label_changed),
+                  NULL, NULL, gst_profiles_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1, G_TYPE_STRING);
+  gst_profile_signals[SIGNAL_DESCRIPTION_CHANGED] =
+    g_signal_new ("description_changed", G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GstProfileClass, description_changed),
+                  NULL, NULL, gst_profiles_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  object_klass->dispose = gst_profile_dispose;
+}
+
+static void
+gst_profile_init (GstProfile *profile)
+{
+  profile->label = NULL;
+  profile->description = NULL;
+  profile->parameters = NULL;
+}
+
+static void
+gst_profile_dispose (GObject *object)
+{
+  GstProfile *profile = GST_PROFILE (object);
+  const GList *item;
+  GstProfileParameter *param;
+
+  g_free (profile->label);
+  g_free (profile->description);
+
+  for (item = profile->parameters; item != NULL; item = item->next) {
+    param = item->data;
+    g_value_unset (&param->value);
+    g_free (param);
+  }
+  g_list_free (profile->parameters);
+  profile->parameters = NULL;
+}
+
+/**
+ * gst_profile_create:
+ * @label: a short, one-line label.
+ * @description: a (longer) description of the profile.
+ * @parameters: a #GList of #GstProfileParameter property/value pairs.
+ *
+ * Creates a new profile with the provided name, description and
+ * parameters.
+ *
+ * Returns: a new #GstProfile.
+ */
+
+GstProfile *
+gst_profile_create (const gchar *label,
+		    const gchar *description,
+		    GList       *parameters)
+{
+  GstProfile *profile = g_object_new (GST_TYPE_PROFILE, NULL);
+
+  profile->label = label ? g_strdup (label) : NULL;
+  profile->description = description ? g_strdup (description) : NULL;
+  profile->parameters = parameters;
+
+  return profile;
+}
+
+/**
+ * gst_profile_get_affected_properties:
+ * @profile: the #GstProfile to check.
+ *
+ * Provides a list of properties that are affected by this
+ * profile.
+ *
+ * Returns: a new #GList of #GParamSpec items. Free after
+ * use with g_list_free().
+ */
+
+GList *
+gst_profile_get_affected_properties (const GstProfile *profile)
+{
+  GList *list = NULL;
+  const GList *item;
+  const GstProfileParameter *param;
+
+  g_return_val_if_fail (profile != NULL, NULL);
+
+  for (item = profile->parameters; item != NULL; item = item->next) {
+    param = item->data;
+    list = g_list_append (list, param->pspec);
+  }
+
+  return list;
+}
+
+/**
+ * gst_profile_get_property_for:
+ * @profile: the #GstProfile to check.
+ * @property: the name of the property to check.
+ *
+ * Provides the value that belongs to a property in this
+ * specific profile.
+ *
+ * Returns: the #GValue for the property.
+ */
+
+const GValue *
+gst_profile_get_property_for (const GstProfile *profile,
+			      const gchar      *property)
+{
+  const GList *item;
+  const GstProfileParameter *param;
+
+  g_return_val_if_fail (profile != NULL, NULL);
+  g_return_val_if_fail (property != NULL, NULL);
+
+  for (item = profile->parameters; item != NULL; item = item->next) {
+    param = item->data;
+    if (!strcmp (property, param->pspec->name))
+      return &param->value;
+  }
+
+  return NULL;
+}
+
+/**
+ * gst_profile_add_parameter:
+ * @profile: the #GstProfile to modify.
+ * @property: the name of the property to add.
+ * @value: the value to add for this property.
+ *
+ * Adds a new property/value pair to the profile.
+ */
+
+void
+gst_profile_add_parameter (GstProfile   *profile,
+			   GParamSpec   *pspec,
+			   const GValue *value)
+{
+  GstProfileParameter *param;
+
+  g_return_if_fail (profile != NULL);
+  g_return_if_fail (pspec != NULL);
+  g_return_if_fail (value != NULL);
+
+  param = g_new0 (GstProfileParameter, 1);
+  param->pspec = pspec;
+  g_value_init (&param->value, G_VALUE_TYPE (value));
+  g_value_copy (value, &param->value);
+
+  profile->parameters = g_list_append (profile->parameters, param);
+
+  g_signal_emit (G_OBJECT (profile),
+		 gst_profile_signals[SIGNAL_PROPERTY_ADDED], 0,
+		 pspec, value);
+}
+
+/**
+ * gst_profile_add_parameter:
+ * @profile: the #GstProfile to modify.
+ * @property: the name of the property to remove.
+ *
+ * Removes a property/value pair from the profile.
+ */
+
+void
+gst_profile_remove_parameter (GstProfile  *profile,
+			      const gchar *property)
+{
+  const GList *item;
+  GstProfileParameter *param;
+
+  g_return_if_fail (profile != NULL);
+  g_return_if_fail (property != NULL);
+
+  for (item = profile->parameters; item != NULL; item = item->next) {
+    param = item->data;
+    if (!strcmp (param->pspec->name, property)) {
+      profile->parameters = g_list_remove (profile->parameters, param);
+
+      g_signal_emit (G_OBJECT (profile),
+		     gst_profile_signals[SIGNAL_PROPERTY_REMOVED], 0,
+		     param->pspec);
+
+      g_value_unset (&param->value);
+      g_free (param);
+
+      break;
+    }
+  }
+}
+
+/**
+ * gst_profile_change_parameter:
+ * @profile: the #GstProfile to modify.
+ * @property: the name of the property to change.
+ * @value: the new value to use for this property.
+ *
+ * Changes a property/value pair from the profile.
+ */
+
+void
+gst_profile_change_parameter (GstProfile   *profile,
+			      const gchar  *property,
+			      const GValue *value)
+{
+  const GList *item;
+  GstProfileParameter *param;
+
+  g_return_if_fail (profile != NULL);
+  g_return_if_fail (property != NULL);
+  g_return_if_fail (value != NULL);
+
+  for (item = profile->parameters; item != NULL; item = item->next) {
+    param = item->data;
+    if (!strcmp (param->pspec->name, property)) {
+      g_value_copy (value, &param->value);
+
+      g_signal_emit (G_OBJECT (profile),
+		     gst_profile_signals[SIGNAL_PROPERTY_CHANGED], 0,
+		     param->pspec, value);
+
+      break;
+    }
+  }
+}
+
+/**
+ * gst_profile_change_label:
+ * @profile: the #GstProfile to modify.
+ * @label: the new label to use for this profile.
+ *
+ * Changes the label of the profile.
+ */
+
+void
+gst_profile_change_label (GstProfile  *profile,
+			  const gchar *label)
+{
+  g_return_if_fail (profile != NULL);
+
+  g_free (profile->label);
+  profile->label = label ? g_strdup (label) : NULL;
+
+  g_signal_emit (G_OBJECT (profile),
+		 gst_profile_signals[SIGNAL_LABEL_CHANGED], 0,
+		 label);
+}
+
+/**
+ * gst_profile_change_description:
+ * @profile: the #GstProfile to modify.
+ * @description: the new description to use for this profile.
+ *
+ * Changes the description of the profile.
+ */
+
+void
+gst_profile_change_description (GstProfile  *profile,
+				const gchar *description)
+{
+  g_return_if_fail (profile != NULL);
+
+  g_free (profile->description);
+  profile->description = description ? g_strdup (description) : NULL;
+
+  g_signal_emit (G_OBJECT (profile),
+		 gst_profile_signals[SIGNAL_DESCRIPTION_CHANGED], 0,
+		 description);
+}
+
+/**
+ * gst_profile_parameter_new:
+ * @pspec: the paramspec of the property to allocate this param for.
+ *
+ * Allocates a param and inits the contained value type.
+ */
+
+GstProfileParameter *
+gst_profile_parameter_new (GParamSpec *pspec)
+{
+  GstProfileParameter *param;
+
+  param = g_new0 (GstProfileParameter, 1);
+  param->pspec = pspec;
+  g_value_init (&param->value, pspec->value_type);
+
+  return param;
+}
+
+/**
+ * gst_profile_parameter_free:
+ * @param: the #GstRecParameter to free
+ *
+ * Frees the memory allocated by the param and its contained value.
+ */
+
+void
+gst_profile_parameter_free (GstProfileParameter *param)
+{
+  g_value_unset (&param->value);
+  g_free (param);
+}
Index: gst-plugins/gst-libs/gst/profiles/profile.h
--- gst-plugins~profiles/gst-libs/gst/profiles/profile.h	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profile.h	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,139 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * profile.h: definition of the profile object
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_PROFILE_H__
+#define __GST_PROFILE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PROFILE \
+  (gst_profile_get_type ())
+#define GST_PROFILE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROFILE, \
+			       GstProfile))
+#define GST_PROFILE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROFILE, \
+			    GstProfileClass))
+#define GST_IS_PROFILE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROFILE))
+#define GST_IS_PROFILE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROFILE))
+
+typedef struct GstProfileParameter {
+  GParamSpec *pspec;
+  GValue      value;
+} GstProfileParameter;
+
+typedef enum {
+  GST_PROFILE_DEFAULT = (1<<0)
+} GstProfileFlags;
+
+#define GST_PROFILE_HAS_FLAG(profile, flag) ((profile) & (flag))
+#define GST_PROFILE_IS_DEFAULT(profile) \
+  GST_PROFILE_HAS_FLAG (profile, GST_PROFILE_FLAG_DEFAULT)
+
+typedef struct _GstProfile {
+  GObject parent;
+
+  /* flags for this profile. Used to identify default
+   * ones from new ones. */
+  GstProfileFlags flags;
+
+  /* label is a few words (single-line),
+   * description can be longer (even multi-line) */
+  gchar *label,
+	*description;
+
+  /* list of GstPropertyParameters */
+  GList *parameters;
+
+  gpointer __reserved[4];
+} GstProfile;
+
+typedef struct _GstProfileClass {
+  GObjectClass parent;
+
+  /* signals */
+  void (* property_added)      (GstProfile       *profile,
+				const GParamSpec *pspec,
+				const GValue     *value);
+  void (* property_removed)    (GstProfile       *profile,
+				const GParamSpec *pspec);
+  void (* property_changed)    (GstProfile       *profile,
+				const GParamSpec *pspec,
+				const GValue     *value);
+  void (* label_changed)       (GstProfile       *profile,
+				const gchar      *label);
+  void (* description_changed) (GstProfile       *profile,
+				const gchar      *description);
+
+  gpointer __reserved[4];
+} GstProfileClass;
+
+GType	gst_profile_get_type                (void);
+
+/*
+ * Create new profile.
+ */
+GstProfile *gst_profile_create              (const gchar       *label,
+					     const gchar       *description,
+					     GList             *parameters);
+
+/*
+ * Profile information functions. After use, free the list
+ * (g_list_free()), but not the contents. The list contains
+ * GParamSpecs.
+ */
+GList *	gst_profile_get_affected_properties (const GstProfile *profile);
+const GValue *
+	gst_profile_get_property_for        (const GstProfile *profile,
+					     const gchar      *property);
+
+/*
+ * Editing profiles is also possible, but (as above)
+ * not on the default ones.
+ */
+void	gst_profile_add_parameter           (GstProfile        *profile,
+					     GParamSpec        *pspec,
+					     const GValue      *value);
+void	gst_profile_remove_parameter        (GstProfile        *profile,
+					     const gchar       *property);
+void	gst_profile_change_parameter        (GstProfile        *profile,
+					     const gchar       *property,
+					     const GValue      *value);
+void	gst_profile_change_label            (GstProfile        *profile,
+					     const gchar       *label);
+void	gst_profile_change_description      (GstProfile        *profile,
+					     const gchar       *description);
+
+/*
+ * Small utility functions for handling parameters.
+ */
+GstProfileParameter *
+	gst_profile_parameter_new           (GParamSpec          *pspec);
+void	gst_profile_parameter_free          (GstProfileParameter *param);
+
+G_END_DECLS
+
+#endif /* __GST_PROFILE_H__ */
Index: gst-plugins/gst-libs/gst/profiles/profilemanager.c
--- gst-plugins~profiles/gst-libs/gst/profiles/profilemanager.c	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profilemanager.c	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,322 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * profilemanager.c: code for handling profiles on an element type
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "profilesmarshal.h"
+#include "profilemanager.h"
+#include "profilexml.h"
+
+/* signals */
+enum {
+  SIGNAL_PROFILE_ADDED,
+  SIGNAL_PROFILE_REMOVED,
+  SIGNAL_PROFILE_MOVED,
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+static void	gst_profile_manager_base_init     (GstProfileManagerInterface *iface);
+static void	gst_profile_manager_base_finalize (GstProfileManagerInterface *iface);
+
+static guint gst_profile_manager_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_profile_manager_get_type (void)
+{
+  static GType gst_profile_manager_type = 0;
+
+  if (!gst_profile_manager_type) {
+    static const GTypeInfo gst_profile_manager_info = {
+      sizeof (GstProfileManagerInterface),
+      (GBaseInitFunc) gst_profile_manager_base_init,
+      (GBaseFinalizeFunc) gst_profile_manager_base_finalize,
+      NULL,
+      NULL,
+      NULL,
+      0,
+      0,
+      NULL,
+    };
+
+    gst_profile_manager_type =
+	g_type_register_static (G_TYPE_INTERFACE,
+				"GstProfileManager",
+				&gst_profile_manager_info, 0);
+    g_type_interface_add_prerequisite (gst_profile_manager_type,
+				       GST_TYPE_ELEMENT);
+  }
+
+  return gst_profile_manager_type;
+}
+
+static void
+gst_profile_manager_base_init (GstProfileManagerInterface *iface)
+{
+  static gboolean initialized = FALSE;
+  
+  if (!initialized) {
+    gst_profile_manager_signals[SIGNAL_PROFILE_ADDED] =
+      g_signal_new ("profile_added",
+		    GST_TYPE_PROFILE_MANAGER, G_SIGNAL_RUN_LAST,
+		    G_STRUCT_OFFSET (GstProfileManagerInterface, profile_added),
+		    NULL, NULL,
+		    gst_profiles_marshal_VOID__OBJECT_UINT, G_TYPE_NONE, 2,
+		    GST_TYPE_PROFILE, G_TYPE_UINT);
+    gst_profile_manager_signals[SIGNAL_PROFILE_REMOVED] =
+      g_signal_new ("profile_removed",
+		    GST_TYPE_PROFILE_MANAGER, G_SIGNAL_RUN_LAST,
+		    G_STRUCT_OFFSET (GstProfileManagerInterface, profile_removed),
+		    NULL, NULL,
+		    gst_profiles_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
+		    GST_TYPE_PROFILE);
+    gst_profile_manager_signals[SIGNAL_PROFILE_MOVED] =
+      g_signal_new ("profile_moved",
+		    GST_TYPE_PROFILE_MANAGER, G_SIGNAL_RUN_LAST,
+		    G_STRUCT_OFFSET (GstProfileManagerInterface, profile_moved),
+		    NULL, NULL,
+		    gst_profiles_marshal_VOID__OBJECT_UINT, G_TYPE_NONE, 2,
+		    GST_TYPE_PROFILE, G_TYPE_UINT);
+      
+    initialized = TRUE;
+  }
+
+  /* no profiles until we're asked to generate the list */
+  iface->loaded = FALSE;
+  iface->profiles = NULL;
+
+  /* default virtual functions */
+  iface->get_default_profiles = NULL;
+}
+
+static void
+gst_profile_manager_base_finalize (GstProfileManagerInterface *iface)
+{
+  GstElementClass *klass = GST_ELEMENT_CLASS (g_type_interface_peek_parent (iface));
+
+  if (iface->loaded && klass->elementfactory && iface->profiles) {
+    gst_profile_xml_save (klass, iface->profiles);
+  }
+}
+
+/**
+ * gst_profile_manager_list_profiles:
+ * @manager: the #GstProfileManager to retrieve the list from.
+ *
+ * Provides a full list of profiles in this manager. This is
+ * both the default profiles provided by the element itself
+ * and user-provided extra profiles.
+ *
+ * Returns: a #GList of #GstProfile items in this manager.
+ */
+
+const GList *
+gst_profile_manager_list_profiles (GstProfileManagerInterface *iface)
+{
+  g_return_val_if_fail (iface != NULL, NULL);
+
+  if (!iface->loaded) {
+    GTypeInterface *iface_type = (GTypeInterface *) iface;
+    GstElementClass *klass = GST_ELEMENT_CLASS (g_type_class_peek (iface_type->g_instance_type));
+    GList *default_profiles = NULL, *extra_profiles = NULL;
+
+    if (iface->get_default_profiles) {
+      const GList *temp = iface->get_default_profiles (klass);
+      if (temp) {
+        default_profiles = g_list_copy ((GList *) temp);
+      }
+    }
+
+    if (klass->elementfactory) {
+      extra_profiles = gst_profile_xml_load (klass);
+    }
+
+    iface->profiles = g_list_concat (default_profiles, extra_profiles);
+    iface->loaded = TRUE;
+  }
+
+  return iface->profiles;
+}
+
+/**
+ * gst_profile_manager_get_profile:
+ * @manager: the #GstProfileManager to get the current profile
+ *           from.
+ *
+ * Compare all current properties from the element against
+ * each of the property/value pairs in all the profiles of
+ * this profile manager to check if one matches. Note that
+ * this isn't a light operation so it shouldn't be used if
+ * not absolutely needed.
+ *
+ * Returns: the current #GstProfile or NULL if none applies.
+ */
+
+const GstProfile *
+gst_profile_manager_get_profile (GstProfileManager *manager)
+{
+  GstProfileManagerInterface *iface;
+  GObject *obj = G_OBJECT (manager);
+  const GList *item, *pitem;
+  const GstProfile *profile;
+  const GstProfileParameter *param;
+  GValue value = { 0 };
+  gboolean same;
+
+  g_return_val_if_fail (manager != NULL, NULL);
+
+  iface = GST_PROFILE_MANAGER_GET_INTERFACE (manager);
+  for (item = gst_profile_manager_list_profiles (iface);
+       item != NULL; item = item->next) {
+    profile = item->data;
+    for (pitem = profile->parameters; pitem != NULL; pitem = pitem->next) {
+      param = pitem->data;
+      g_value_init (&value, G_VALUE_TYPE (&param->value));
+      g_object_get (obj, param->pspec->name, &value, NULL);
+      same = (gst_value_compare (&value, &param->value) == GST_VALUE_EQUAL);
+      g_value_unset (&value);
+      if (!same)
+        break;
+    }
+
+    /* If we finished the whole loop, all parameters are equal and we have
+     * thus found an interface compatible with the current property stack. */
+    if (!pitem)
+      return profile;
+  }
+
+  return NULL;
+}
+
+/**
+ * gst_profile_manager_set_profile:
+ * @manager: the #GstProfileManager to set the profile on.
+ * @profile: the #GstProfile to activate.
+ *
+ * Sets all property/value pairs of this profile on the
+ * element.
+ */
+
+void
+gst_profile_manager_set_profile (GstProfileManager *manager,
+				 const GstProfile  *profile)
+{
+  GObject *obj = G_OBJECT (manager);
+  const GList *item;
+  const GstProfileParameter *param;
+
+  g_return_if_fail (manager != NULL);
+  g_return_if_fail (profile != NULL);
+
+  /* This is as easy as it can get - we just set each of the affected
+   * properties to the value that belongs to it in this profile. */
+  for (item = profile->parameters; item != NULL; item = item->next) {
+    param = item->data;
+    g_object_set (obj, param->pspec->name, &param->value, NULL);
+  }
+}
+
+/**
+ * gst_profile_manager_add_profile:
+ * @manager: the #GstProfileManager to add the profile to.
+ * @profile: the #GstProfile to add.
+ * @position: position in the list of profiles to add the
+ *            new profile to. -1 is at the end.
+ *
+ * Adds a new profile to the profile manager.
+ */
+
+void
+gst_profile_manager_add_profile (GstProfileManagerInterface *iface,
+				 GstProfile                 *profile,
+				 guint                       position)
+{
+  g_return_if_fail (iface != NULL);
+  g_return_if_fail (profile != NULL);
+
+  if (position == (guint) -1) {
+    position = g_list_length (iface->profiles);
+  }
+  iface->profiles = g_list_insert (iface->profiles, profile, position);
+
+  /*g_signal_emit (G_OBJECT (manager),
+		 gst_profile_manager_signals[SIGNAL_PROFILE_ADDED], 0,
+		 profile, position);*/
+}
+
+/**
+ * gst_profile_manager_remove_profile:
+ * @manager: the #GstProfileManager to remove the profile
+ *           from.
+ * @profile: the #GstProfile to remove.
+ *
+ * Removes the given profile from the profile manager.
+ */
+
+void
+gst_profile_manager_remove_profile (GstProfileManagerInterface *iface,
+				    GstProfile                 *profile)
+{
+  g_return_if_fail (iface != NULL);
+  g_return_if_fail (profile != NULL);
+
+  iface->profiles = g_list_remove (iface->profiles, profile);
+
+  /*g_signal_emit (G_OBJECT (manager),
+		 gst_profile_manager_signals[SIGNAL_PROFILE_REMOVED], 0,
+		 profile);*/
+
+  g_object_unref (G_OBJECT (profile));
+}
+
+/**
+ * gst_profile_manager_move_profile:
+ * @manager: the #GstProfileManager to operate on.
+ * @profile: the #GstProfile to move.
+ * @position: the new position in the profile list of the
+ *            manager to place the profile at.
+ *
+ * Moves the given profile to a different position in the
+ * list of profiles inside the profile manager.
+ */
+
+void
+gst_profile_manager_move_profile (GstProfileManagerInterface *iface,
+				  GstProfile                 *profile,
+				  guint                       position)
+{
+  g_return_if_fail (iface != NULL);
+  g_return_if_fail (profile != NULL);
+
+  iface->profiles = g_list_remove (iface->profiles, profile);
+  if (position == (guint) -1) {
+    position = g_list_length (iface->profiles);
+  }
+  iface->profiles = g_list_insert (iface->profiles, profile, position);
+
+  /*g_signal_emit (G_OBJECT (manager),
+		 gst_profile_manager_signals[SIGNAL_PROFILE_MOVED], 0,
+		 profile, position);*/
+}
Index: gst-plugins/gst-libs/gst/profiles/profilemanager.h
--- gst-plugins~profiles/gst-libs/gst/profiles/profilemanager.h	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profilemanager.h	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,110 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * profilemanager.h: definition of a profile manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_PROFILE_MANAGER_H__
+#define __GST_PROFILE_MANAGER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gst/gstelement.h>
+#include <gst/profiles/profile.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PROFILE_MANAGER \
+  (gst_profile_manager_get_type ())
+#define GST_PROFILE_MANAGER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROFILE_MANAGER, \
+			       GstProfileManager))
+#define GST_PROFILE_MANAGER_INTERFACE(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROFILE_MANAGER, \
+			    GstProfileManagerInterface))
+#define GST_IS_PROFILE_MANAGER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROFILE_MANAGER))
+#define GST_IS_PROFILE_MANAGER_INTERFACE(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROFILE_MANAGER))
+#define GST_PROFILE_MANAGER_GET_INTERFACE(inst) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_PROFILE_MANAGER, \
+				  GstProfileManagerInterface))
+
+/* a manager is the interface for the class/instance */
+typedef struct _GstProfileManager GstProfileManager;
+
+typedef struct _GstProfileManagerInterface {
+  GTypeInterface iface;
+
+  /* list of profiles (both defaults + extra) */
+  gboolean loaded;
+  GList *profiles;
+
+  /* signals */
+  void (* profile_added)   (GstProfileManager *manager,
+			    const GstProfile  *profile,
+			    guint              position);
+  void (* profile_removed) (GstProfileManager *manager,
+			    const GstProfile  *profile);
+  void (* profile_moved)   (GstProfileManager *manager,
+			    const GstProfile  *profile,
+			    guint              position);
+
+  /* virtual functions */
+  const GList * (* get_default_profiles) (GstElementClass *klass);
+
+  gpointer __reserved[4];
+} GstProfileManagerInterface;
+
+GType	gst_profile_manager_get_type      (void);
+
+/*
+ * Get the full list of profiles. On first call, this will
+ * retrieve default profiles and load the extras from a file
+ */
+const GList *
+	gst_profile_manager_list_profiles (GstProfileManagerInterface *iface);
+
+/*
+ * Get/Set current profile. Get is tricky (don't call it too
+ * often) because it has to compare each property with the
+ * asosciated value in each profile...
+ */
+const GstProfile *
+	gst_profile_manager_get_profile   (GstProfileManager *manager);
+void	gst_profile_manager_set_profile   (GstProfileManager *manager,
+					   const GstProfile  *profile);
+
+/*
+ * Functions to add/remove custom profiles. You may never
+ * touch the default profiles.
+ * Note1: those function are simply GList wrappers.
+ * Note2: add with position=-1 is append, 0 is prepend.
+ */
+void	gst_profile_manager_add_profile     (GstProfileManagerInterface *iface,
+					     GstProfile        *profile,
+					     guint              position);
+void	gst_profile_manager_remove_profile  (GstProfileManagerInterface *iface,
+					     GstProfile        *profile);
+void	gst_profile_manager_move_profile    (GstProfileManagerInterface *iface,
+					     GstProfile        *profile,
+					     guint              position);
+
+G_END_DECLS
+
+#endif /* __GST_PROFILE_MANAGER_H__ */
Index: gst-plugins/gst-libs/gst/profiles/profilesmarshal.list
--- gst-plugins~profiles/gst-libs/gst/profiles/profilesmarshal.list	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profilesmarshal.list	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,5 @@
+VOID:OBJECT,UINT
+VOID:OBJECT
+VOID:POINTER,POINTER
+VOID:POINTER
+VOID:STRING
Index: gst-plugins/gst-libs/gst/profiles/profilexml.c
--- gst-plugins~profiles/gst-libs/gst/profiles/profilexml.c	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profilexml.c	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,384 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * profilexml.c: functions for loading/saving profiles to XML
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <gst/gst.h>
+#include <libxml/parser.h>
+
+#include "profilexml.h"
+#include "profile.h"
+
+/* Locations where we can find our stuff... */
+//hacks
+#define GST_MAJORMINOR "0.7"
+#define GST_CACHE_DIR "/home/rbultje/projects/gstreamer/gstreamer"
+//end hacks
+#define PROFILES_FILENAME "profiles.xml"
+#define GLOBAL_PROFILE_FILE GLOBAL_REGISTRY_DIR "/" PROFILES_FILENAME
+#define LOCAL_PROFILE_FILE  LOCAL_REGISTRY_DIR "/" PROFILES_FILENAME
+
+typedef struct _GstProfileXMLReadInfo {
+  xmlDoc  *doc;
+  xmlNs   *ns;
+  xmlNode *root;
+  time_t   last_mod;
+  gboolean exists;
+  gchar   *filename;
+} GstProfileXMLReadInfo;
+
+/*
+ * This is the XML data for global (system-wide) and
+ * local (user-specific) profiles.
+ */
+static GstProfileXMLReadInfo global = { NULL, NULL, NULL, 0, TRUE,
+					GLOBAL_PROFILE_FILE },
+			     local  = { NULL, NULL, NULL, 0, TRUE, NULL };
+static gboolean first = TRUE;
+
+/*
+ * XML file read-out and update routine.
+ */
+
+static gboolean
+gst_profile_xml_update (GstProfileXMLReadInfo *info,
+			gboolean               first)
+{
+  struct stat s;
+
+  /* local filename */
+  if (!local.filename)
+    local.filename = g_strdup_printf ("%s/" LOCAL_PROFILE_FILE,
+				      g_get_home_dir ());
+
+  /* check file status */
+  if (stat (info->filename, &s) < 0) {
+    if (info->exists == TRUE) {
+      GST_WARNING ("Failed to stat file %s: %s",
+		   info->filename, g_strerror (errno));
+      info->exists = FALSE;
+    }
+    return FALSE;
+  }
+
+  /* did the file renew? */
+  if (!first && info->last_mod == s.st_mtime) {
+    return (info->doc != NULL);
+  }
+
+  /* yes, it did! */
+  info->last_mod = s.st_mtime;
+  info->exists   = TRUE;
+  if (info->doc) {
+    xmlFreeDoc (info->doc);
+    info->doc = NULL;
+  }
+
+  /* open file */
+  if (!(info->doc = xmlParseFile (info->filename))) {
+    GST_WARNING ("Failed to open file %s: %s",
+		 info->filename, g_strerror (errno));
+    return FALSE;
+  }
+
+  /* check file type */
+  if (!(info->root = xmlDocGetRootElement (info->doc))) {
+    GST_WARNING ("XML document %s has no data", info->filename);
+    goto error;
+  }
+  if (!strcmp (info->root->name, "gst-profiles")) {
+    GST_WARNING ("XML document %s is of wrong type %s",
+		 info->filename, info->root->name);
+    goto error;
+  }
+  if (!(info->ns = xmlSearchNsByHref (info->doc, info->root,
+			"http://gstreamer.net/gst-core/1.0/"))) {
+    GST_WARNING ("XML document %s has no root namespace", info->filename);
+    goto error;
+  }
+
+  return (info->doc != NULL);
+
+error:
+  xmlFreeDoc (info->doc);
+  info->doc = NULL;
+  return FALSE;
+}
+
+/*
+ * Routines for adding/modifying XML nodes.
+ */
+
+static gboolean
+gst_profile_xml_write (GstProfileXMLReadInfo *info,
+		       GstElementClass       *klass,
+		       const GList           *profiles)
+{
+  struct stat s;
+  xmlNode *field, *node, *nnode, *pnode, *tnode;
+  const gchar *name = GST_PLUGIN_FEATURE (klass->elementfactory)->name;
+  const GList *item, *pitem;
+  GValue strval = { 0 };
+
+  if (stat (info->filename, &s) < 0) {
+    gchar *path = g_path_get_basename (info->filename);
+    mkdir (path, 0);
+    if (stat (path, &s) < 0) {
+      GST_WARNING ("File %s and path %s could not be statted: %s",
+		   info->filename, path, g_strerror (errno));
+      g_free (path);
+      return FALSE;
+    }
+    g_free (path);
+  }
+
+  /* can we write? */
+  if (!(geteuid () == 0 || s.st_mode & S_IWOTH ||
+        (s.st_uid == geteuid () && s.st_mode & S_IWUSR) ||
+        (s.st_gid == getegid () && s.st_mode & S_IWGRP))) {
+    GST_WARNING ("Cannot open %s", info->filename);
+    return FALSE;
+  }
+
+  g_value_init (&strval, G_TYPE_STRING);
+
+  /* create new child node */
+  node = xmlNewNode (info->ns, "element");
+  nnode = xmlNewChild (node, info->ns, "name", name);
+  nnode = xmlNewChild (node, info->ns, "profiles", NULL);
+  for (item = profiles; item != NULL; item = item->next) {
+    GstProfile *profile = item->data;
+
+    pnode = xmlNewChild (nnode, info->ns, "profile", NULL);
+    tnode = xmlNewChild (pnode, info->ns, "name", profile->label);
+    if (profile->description)
+      tnode = xmlNewChild (pnode, info->ns, "description",
+			   profile->description);
+    tnode = xmlNewChild (pnode, info->ns, "parameterlist", NULL);
+
+    for (pitem = profile->parameters; pitem != NULL; pitem = pitem->next) {
+      xmlNode *anode, *vnode;
+      GstProfileParameter *param = pitem->data;
+
+      anode = xmlNewChild (tnode, info->ns, "parameter", NULL);
+      vnode = xmlNewChild (anode, info->ns, "property", param->pspec->name);
+      g_value_transform (&param->value, &strval);
+      vnode = xmlNewChild (anode, info->ns, "value",
+			   g_value_get_string (&strval));
+    }
+  }
+
+  g_value_unset (&strval);
+
+  /* update document */
+  for (field = info->root->xmlChildrenNode;
+       field != NULL; field = field->next) {
+    if (!strcmp (field->name, name)) {
+      xmlReplaceNode (field, node);
+      break;
+    }
+  }
+  if (!field)
+    xmlAddChild (info->root, node);
+
+  /* save away */
+  xmlSaveFile (info->filename, info->doc);
+
+  return FALSE;
+}
+
+gboolean
+gst_profile_xml_save (GstElementClass *klass,
+		      const GList     *profiles)
+{
+  gboolean written = FALSE;
+
+  g_return_val_if_fail (klass->elementfactory != NULL, FALSE);
+
+  GST_INFO ("Saving profiles for element %s to disk",
+	    GST_PLUGIN_FEATURE (klass->elementfactory)->name);
+
+  if (!written && gst_profile_xml_update (&global, first))
+    written = gst_profile_xml_write (&global, klass, profiles);
+
+  if (!written && gst_profile_xml_update (&local, first))
+    written = gst_profile_xml_write (&local, klass, profiles);
+
+  if (!written) {
+    GST_WARNING ("Failed to write to either local or global XML");
+  }
+  first = FALSE;
+
+  return written;
+}
+
+/*
+ * Routines for finding data in XML documents.
+ */
+
+static GstProfile *
+gst_profile_xml_read_from_node (GstElementClass *klass,
+				xmlNode         *node)
+{
+  GObjectClass *oklass = G_OBJECT_CLASS (klass);
+  GstProfile *profile = NULL;
+  gchar *description = NULL, *name = NULL;
+  GList *values = NULL;
+  xmlNode *field;
+
+  /* read subfields */
+  for (field = node->xmlChildrenNode;
+       field != NULL; field = field->next) {
+    if (!strcmp (field->name, "name")) {
+      name = field->content;
+    } else if (!strcmp (field->name, "description")) {
+      description = field->content;
+    } else if (!strcmp (field->name, "parameterlist")) {
+      xmlNode *vfield;
+
+      g_list_foreach (values, (GFunc) gst_profile_parameter_free, NULL);
+      values = NULL;
+
+      for (vfield = field->xmlChildrenNode;
+	   vfield != NULL; vfield = vfield->next) {
+        if (!strcmp (vfield->name, "parameter")) {
+          gchar *property = NULL, *value = NULL;
+          xmlNode *cfield;
+
+          for (cfield = vfield->xmlChildrenNode;
+	       cfield != NULL; cfield = cfield->next) {
+
+            if (!strcmp (cfield->name, "property")) {
+              property = vfield->content;
+            } else if (!strcmp (cfield->name, "value")) {
+              value = vfield->content;
+            }
+          }
+
+          if (property) {
+            GstProfileParameter *param;
+            GParamSpec *pspec;
+
+            if (!(pspec = g_object_class_find_property (oklass, property))) {
+              GST_WARNING ("Unknown property %s for element %s",
+			   property, node->content);
+              continue;
+            }
+            param = gst_profile_parameter_new (pspec);
+            if (value) {
+              /* read */
+              GValue strval = { 0 };
+
+              g_value_init (&strval, G_TYPE_STRING);
+              g_value_set_string (&strval, value);
+              g_value_transform (&strval, &param->value);
+              g_value_unset (&strval);
+            } else {
+              /* default */
+              g_param_value_defaults (pspec, &param->value);
+            }
+            values = g_list_append (values, param);
+          }
+        }
+      }
+    }
+  }
+
+  /* use */
+  if (name) {
+    profile = gst_profile_create (name, description, values);
+  } else {
+    g_list_foreach (values, (GFunc) gst_profile_parameter_free, NULL);
+  }
+
+  return profile;
+}
+
+static GList *
+gst_profile_xml_read (GList                       *list,
+		      const GstProfileXMLReadInfo *info,
+		      GstElementClass             *klass)
+{
+  xmlNode *field;
+  const gchar *name = GST_PLUGIN_FEATURE (klass->elementfactory)->name;
+
+  g_return_val_if_fail (info->doc != NULL, NULL);
+
+  for (field = info->root->xmlChildrenNode;
+       field != NULL; field = field->next) {
+    if (!strcmp (field->name, "element") &&
+        field->ns == info->ns) {
+      xmlNode *pfield = field->xmlChildrenNode, *cfield;
+
+      /* first is name:element */
+      if (strcmp (pfield->name, "name") ||
+          strcmp (pfield->content, name))
+        continue;
+
+      /* second field is profiles */
+      if (!(pfield = pfield->next) ||
+          strcmp (pfield->name, "profiles"))
+        continue;
+
+      /* each kid is one profile */
+      for (cfield = pfield->xmlChildrenNode;
+           cfield != NULL; cfield = cfield->next) {
+        if (!strcmp (cfield->name, "profile")) {
+          GstProfile *profile;
+
+          profile = gst_profile_xml_read_from_node (klass, pfield);
+          list = g_list_append (list, profile);
+        }
+      }
+      break;
+    }
+  }
+
+  return list;
+}
+
+GList *
+gst_profile_xml_load (GstElementClass *klass)
+{
+  GList *profiles = NULL;
+
+  g_return_val_if_fail (klass->elementfactory != NULL, NULL);
+
+  GST_INFO ("Loading profiles for element %s from disk",
+	    GST_PLUGIN_FEATURE (klass->elementfactory)->name);
+
+  if (gst_profile_xml_update (&global, first))
+    profiles = gst_profile_xml_read (profiles, &global, klass);
+
+  if (gst_profile_xml_update (&local, first))
+    profiles = gst_profile_xml_read (profiles, &local, klass);
+
+  first = FALSE;
+
+  return profiles;
+}
Index: gst-plugins/gst-libs/gst/profiles/profilexml.h
--- gst-plugins~profiles/gst-libs/gst/profiles/profilexml.h	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/profilexml.h	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,35 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * profilexml.h: functions for loading/saving profiles to XML
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_PROFILE_XML_H__
+#define __GST_PROFILE_XML_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean gst_profile_xml_save (GstElementClass *klass,
+			       const GList     *profiles);
+GList *	 gst_profile_xml_load (GstElementClass *klass);
+
+G_END_DECLS
+
+#endif /* __GST_PROFILE_MANAGER_H__ */
Index: gst-plugins/gst-libs/gst/profiles/showprofile.c
--- gst-plugins~profiles/gst-libs/gst/profiles/showprofile.c	2004-03-25 22:53:35.000000000 +0100
+++ gst-plugins/gst-libs/gst/profiles/showprofile.c	2004-03-25 22:53:35.000000000 +0100
@@ -0,0 +1,136 @@
+/* GStreamer Profiles
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * showprofile.c: example application showing profiles for plugins
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/profiles/profilemanager.h>
+
+static void
+show_all_elements (void)
+{
+  const GList *elements;
+  GstElementFactory *factory;
+  GstElementClass *klass;
+
+  /* get list of elements */
+  for (elements = gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY);
+       elements != NULL; elements = elements->next) {
+    factory = (GstElementFactory *) elements->data;
+    if (!gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
+      g_warning ("Failed to load plugin feature \"%s\"",
+		 GST_PLUGIN_FEATURE (factory)->name);
+      continue;
+    }
+    if (!factory->type) {
+      g_warning ("Plugin feature %s has no type",
+		 GST_PLUGIN_FEATURE (factory)->name);
+      continue;
+    }
+    klass = g_type_class_ref (factory->type);
+    if (g_type_interface_peek (klass, GST_TYPE_PROFILE_MANAGER)) {
+      g_print ("%s\n", GST_PLUGIN_FEATURE (factory)->name);
+    }
+    g_type_class_unref (klass);
+    gst_plugin_feature_unload_thyself (GST_PLUGIN_FEATURE (factory));
+  }
+}
+
+static void
+show_elements (gchar *elements[],
+	       gint   num_elements)
+{
+  GstProfileManagerInterface *iface;
+  GstElementFactory *factory;
+  GstElementClass *klass;
+  GstProfile *profile;
+  GParamSpec *pspec;
+  const GValue *value;
+  GValue display_value = { 0 };
+  gint i;
+  const GList *profiles, *parameters;
+
+  for (i = 0; i < num_elements; i++) {
+    factory = gst_element_factory_find (elements[i]);
+    if (!factory) {
+      g_warning ("Failed to create instance for element \"%s\"",
+		 elements[i]);
+      continue;
+    }
+    if (!gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
+      g_warning ("Failed to load plugin feature \"%s\"",
+		 elements[i]);
+      continue;
+    }
+    if (!factory->type) {
+      g_warning ("Plugin feature %s has no type",
+		 elements[i]);
+      continue;
+    }
+    klass = g_type_class_ref (factory->type);
+    if (!(iface = g_type_interface_peek (klass, GST_TYPE_PROFILE_MANAGER))) {
+      g_warning ("Element \"%s\" does not implement a profile manager",
+		 elements[i]);
+      goto end;
+    }
+    klass->elementfactory = factory;
+
+    g_print ("Element \"%s\":\n", elements[i]);
+    if (!(profiles = gst_profile_manager_list_profiles (iface)))
+      g_print ("  (none)\n");
+    for (; profiles != NULL; profiles = profiles->next) {
+      GList *parameter_static_list;
+      profile = profiles->data;
+      g_print (" * Profile \"%s\":\n", profile->label);
+      parameter_static_list = gst_profile_get_affected_properties (profile);
+      for (parameters = parameter_static_list;
+	   parameters != NULL; parameters = parameters->next) {
+        pspec = parameters->data;
+        value = gst_profile_get_property_for (profile, pspec->name);
+        g_value_init (&display_value, G_TYPE_STRING);
+        g_value_transform (value, &display_value);
+        g_print ("    %s:\t%s\n", pspec->name,
+		 g_value_get_string (&display_value));
+        g_value_unset (&display_value);
+      }
+      g_list_free (parameter_static_list);
+    }
+end:
+    g_type_class_unref (klass);
+    gst_plugin_feature_unload_thyself (GST_PLUGIN_FEATURE (factory));
+  }
+}
+
+gint
+main (gint   argc,
+      gchar *argv[])
+{
+  gst_init (&argc, &argv);
+
+  if (argc == 1)
+    show_all_elements ();
+  else
+    show_elements (argv + 1, argc - 1);
+
+  return 0;
+}
Index: gst-plugins/pkgconfig/Makefile.am
--- gst-plugins~profiles/pkgconfig/Makefile.am	2004-03-15 22:03:38.000000000 +0100
+++ gst-plugins/pkgconfig/Makefile.am	2004-03-28 18:43:28.000000000 +0200
@@ -13,14 +13,16 @@
 	gstreamer-libs-@GST_MAJORMINOR@.pc \
 	gstreamer-media-info-@GST_MAJORMINOR@.pc \
 	gstreamer-play-@GST_MAJORMINOR@.pc \
-	gstreamer-plugins-@GST_MAJORMINOR@.pc
+	gstreamer-plugins-@GST_MAJORMINOR@.pc \
+	gstreamer-profiles-@GST_MAJORMINOR@.pc
 pcverfiles_uninstalled = \
 	$(GCONF_PC_UNINSTALLED) \
 	gstreamer-interfaces-@GST_MAJORMINOR@-uninstalled.pc \
 	gstreamer-libs-@GST_MAJORMINOR@-uninstalled.pc \
 	gstreamer-media-info-@GST_MAJORMINOR@-uninstalled.pc \
 	gstreamer-play-@GST_MAJORMINOR@-uninstalled.pc \
-	gstreamer-plugins-@GST_MAJORMINOR@-uninstalled.pc
+	gstreamer-plugins-@GST_MAJORMINOR@-uninstalled.pc \
+	gstreamer-profiles-@GST_MAJORMINOR@-uninstalled.pc
 
 pcverfiles_gconf = $(GCONF_PC) $(GCONF_PC_UNINSTALLED)
 all-local: $(pcverfiles) $(pcverfiles_uninstalled)
@@ -41,7 +43,8 @@
            gstreamer-libs.pc.in gstreamer-libs-uninstalled.pc.in \
            gstreamer-media-info.pc.in gstreamer-media-info-uninstalled.pc.in \
            gstreamer-play.pc.in gstreamer-play-uninstalled.pc.in \
-           gstreamer-plugins.pc.in gstreamer-plugins-uninstalled.pc.in
+           gstreamer-plugins.pc.in gstreamer-plugins-uninstalled.pc.in \
+           gstreamer-profiles.pc.in gstreamer-profiles-uninstalled.pc.in
 
 DISTCLEANFILES = $(pcinfiles:.in=)
 EXTRA_DIST = $(pcinfiles)
Index: gst-plugins/pkgconfig/gstreamer-profiles.pc.in
--- gst-plugins~profiles/pkgconfig/gstreamer-profiles.pc.in	2004-03-28 18:43:37.000000000 +0200
+++ gst-plugins/pkgconfig/gstreamer-profiles.pc.in	2004-03-28 18:46:54.000000000 +0200
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/gstreamer-@GST_MAJORMINOR@
+
+Name: GStreamer Encoding Profile Libraries
+Description: Streaming-media framework, encoding profile libraries
+Requires: gstreamer-@GST_MAJORMINOR@
+Version: @VERSION@
+
+Libs: -L${libdir} -lgstprofiles-@GST_MAJORMINOR@
+Cflags: -I${includedir}
Index: gst-plugins/pkgconfig/gstreamer-profiles-uninstalled.pc.in
--- gst-plugins~profiles/pkgconfig/gstreamer-profiles-uninstalled.pc.in	2004-03-28 18:43:44.000000000 +0200
+++ gst-plugins/pkgconfig/gstreamer-profiles-uninstalled.pc.in	2004-03-28 18:47:29.000000000 +0200
@@ -0,0 +1,12 @@
+prefix=
+exec_prefix=
+libdir=${pcfiledir}/../gst-libs/gst/profiles
+includedir=${pcfiledir}/../gst-libs
+
+Name: GStreamer Encoding Profile Library, uninstalled
+Description: Streaming-media framework, encoding profile libraries, not installed
+Requires: gstreamer-@GST_MAJORMINOR@
+Version: @VERSION@
+
+Libs: ${libdir}/libgstprofiles-@GST_MAJORMINOR@.la
+Cflags: -I${includedir}
