Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst-libs / gst / pbutils / encoding-target.c
index faee8c3..bb8223d 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-#include <locale.h>
-#include <string.h>
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+
+#include <locale.h>
+#include <string.h>
 #include "encoding-target.h"
 
 /*
@@ -30,7 +31,7 @@
  *
  * GKeyFile style.
  *
- * [_gstencodingtarget_]
+ * [GStreamer Encoding Target]
  * name : <name>
  * category : <category>
  * description : <description> #translatable
@@ -59,7 +60,7 @@
  * $HOME/gstreamer-GST_MAJORMINOR/encoding-profile
  *
  * Naming convention
- *   $(target.category)/$(target.name).gstprof
+ *   $(target.category)/$(target.name).gep
  *
  * Naming restrictions:
  *  lowercase ASCII letter for the first character
  */
 
 
-#define GST_ENCODING_TARGET_HEADER "_gstencodingtarget_"
+#define GST_ENCODING_TARGET_HEADER "GStreamer Encoding Target"
+#define GST_ENCODING_TARGET_DIRECTORY "encoding-profiles"
+#define GST_ENCODING_TARGET_SUFFIX ".gep"
 
 struct _GstEncodingTarget
 {
-  GstMiniObject parent;
+  GObject parent;
 
   gchar *name;
   gchar *category;
@@ -82,7 +85,7 @@ struct _GstEncodingTarget
   gchar *keyfile;
 };
 
-G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, GST_TYPE_MINI_OBJECT);
+G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, G_TYPE_OBJECT);
 
 static void
 gst_encoding_target_init (GstEncodingTarget * target)
@@ -91,8 +94,10 @@ gst_encoding_target_init (GstEncodingTarget * target)
 }
 
 static void
-gst_encoding_target_finalize (GstEncodingTarget * target)
+gst_encoding_target_finalize (GObject * object)
 {
+  GstEncodingTarget *target = (GstEncodingTarget *) object;
+
   GST_DEBUG ("Finalizing");
 
   if (target->name)
@@ -102,15 +107,14 @@ gst_encoding_target_finalize (GstEncodingTarget * target)
   if (target->description)
     g_free (target->description);
 
-  g_list_foreach (target->profiles, (GFunc) gst_mini_object_unref, NULL);
+  g_list_foreach (target->profiles, (GFunc) g_object_unref, NULL);
   g_list_free (target->profiles);
 }
 
 static void
-gst_encoding_target_class_init (GstMiniObjectClass * klass)
+gst_encoding_target_class_init (GObjectClass * klass)
 {
-  klass->finalize =
-      (GstMiniObjectFinalizeFunction) gst_encoding_target_finalize;
+  klass->finalize = gst_encoding_target_finalize;
 }
 
 /**
@@ -133,7 +137,8 @@ gst_encoding_target_get_name (GstEncodingTarget * target)
  *
  * Since: 0.10.32
  *
- * Returns: (transfer none): The category of the @target.
+ * Returns: (transfer none): The category of the @target. For example:
+ * #GST_ENCODING_CATEGORY_DEVICE.
  */
 const gchar *
 gst_encoding_target_get_category (GstEncodingTarget * target)
@@ -238,7 +243,7 @@ validate_name (const gchar * name)
  * gst_encoding_target_new:
  * @name: The name of the target.
  * @category: (transfer none): The name of the category to which this @target
- * belongs.
+ * belongs. For example: #GST_ENCODING_CATEGORY_DEVICE.
  * @description: (transfer none): A description of #GstEncodingTarget in the
  * current locale.
  * @profiles: (transfer none) (element-type Gst.EncodingProfile): A #GList of
@@ -250,6 +255,11 @@ validate_name (const gchar * name)
  * first character, followed by either lowercase ASCII letters, digits or
  * hyphens ('-').
  *
+ * The @category <emphasis>should</emphasis> be one of the existing
+ * well-defined categories, like #GST_ENCODING_CATEGORY_DEVICE, but it
+ * <emphasis>can</emphasis> be a application or user specific category if
+ * needed.
+ *
  * Since: 0.10.32
  *
  * Returns: (transfer full): The newly created #GstEncodingTarget or %NULL if
@@ -272,7 +282,7 @@ gst_encoding_target_new (const gchar * name, const gchar * category,
   if (!validate_name (category))
     goto invalid_category;
 
-  res = (GstEncodingTarget *) gst_mini_object_new (GST_TYPE_ENCODING_TARGET);
+  res = (GstEncodingTarget *) g_object_new (GST_TYPE_ENCODING_TARGET, NULL);
   res->name = g_strdup (name);
   res->category = g_strdup (category);
   res->description = g_strdup (description);
@@ -305,7 +315,8 @@ invalid_category:
  * @target: the #GstEncodingTarget to add a profile to
  * @profile: (transfer full): the #GstEncodingProfile to add
  *
- * Adds the given @profile to the @target.
+ * Adds the given @profile to the @target. Each added profile must have
+ * a unique name within the profile.
  *
  * The @target will steal a reference to the @profile. If you wish to use
  * the profile after calling this method, you should increase its reference
@@ -399,6 +410,36 @@ serialize_stream_profiles (GKeyFile * out, GstEncodingProfile * sprof,
   return TRUE;
 }
 
+static gchar *
+get_locale (void)
+{
+  const char *loc = NULL;
+  gchar *ret;
+
+#ifdef ENABLE_NLS
+#if defined(LC_MESSAGES)
+  loc = setlocale (LC_MESSAGES, NULL);
+  GST_LOG ("LC_MESSAGES: %s", GST_STR_NULL (loc));
+#elif defined(LC_ALL)
+  loc = setlocale (LC_ALL, NULL);
+  GST_LOG ("LC_ALL: %s", GST_STR_NULL (loc));
+#else
+  GST_LOG ("Neither LC_ALL nor LC_MESSAGES defined");
+#endif
+#else /* !ENABLE_NLS */
+  GST_LOG ("i18n disabled");
+#endif
+
+  if (loc == NULL || g_ascii_strncasecmp (loc, "en", 2) == 0)
+    return NULL;
+
+  /* en_GB.UTF-8 => en */
+  ret = g_ascii_strdown (loc, -1);
+  ret = g_strcanon (ret, "abcdefghijklmnopqrstuvwxyz", '\0');
+  GST_LOG ("using locale: %s", ret);
+  return ret;
+}
+
 /* Serialize the top-level profiles
  * Note: They don't have to be containerprofiles */
 static gboolean
@@ -408,25 +449,32 @@ serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof)
   const GList *tmp;
   guint i;
   const gchar *profname, *profdesc, *profpreset, *proftype;
-  const GstCaps *profformat, *profrestriction;
+  const GstCaps *profformat;
 
   profname = gst_encoding_profile_get_name (prof);
   profdesc = gst_encoding_profile_get_description (prof);
   profformat = gst_encoding_profile_get_format (prof);
   profpreset = gst_encoding_profile_get_preset (prof);
   proftype = gst_encoding_profile_get_type_nick (prof);
-  profrestriction = gst_encoding_profile_get_restriction (prof);
 
   profgroupname = g_strdup_printf ("profile-%s", profname);
 
   g_key_file_set_string (out, profgroupname, "name", profname);
 
-  g_key_file_set_value (out, profgroupname, "type",
-      gst_encoding_profile_get_type_nick (prof));
+  g_key_file_set_value (out, profgroupname, "type", proftype);
 
-  if (profdesc)
-    g_key_file_set_locale_string (out, profgroupname, "description",
-        setlocale (LC_ALL, NULL), profdesc);
+  if (profdesc) {
+    gchar *locale;
+
+    locale = get_locale ();
+    if (locale != NULL) {
+      g_key_file_set_locale_string (out, profgroupname, "description",
+          locale, profdesc);
+      g_free (locale);
+    } else {
+      g_key_file_set_string (out, profgroupname, "description", profdesc);
+    }
+  }
   if (profformat) {
     gchar *tmpc = gst_caps_to_string (profformat);
     g_key_file_set_string (out, profgroupname, "format", tmpc);
@@ -524,11 +572,25 @@ parse_encoding_profile (GKeyFile * in, gchar * parentprofilename,
   pname = g_key_file_get_value (in, profilename, "name", NULL);
 
   /* First try to get localized description */
-  description =
-      g_key_file_get_locale_string (in, profilename, "description",
-      setlocale (LC_ALL, NULL), NULL);
-  if (description == NULL)
-    description = g_key_file_get_value (in, profilename, "description", NULL);
+  {
+    gchar *locale;
+
+    locale = get_locale ();
+    if (locale != NULL) {
+      /* will try to fall back to untranslated string if no translation found */
+      description = g_key_file_get_locale_string (in, profilename,
+          "description", locale, NULL);
+      g_free (locale);
+    } else {
+      description =
+          g_key_file_get_string (in, profilename, "description", NULL);
+    }
+  }
+
+  /* Note: a missing description is normal for non-container profiles */
+  if (description == NULL) {
+    GST_LOG ("Missing 'description' field for streamprofile %s", profilename);
+  }
 
   /* Parse the remaining fields */
   proftype = g_key_file_get_value (in, profilename, "type", NULL);
@@ -644,6 +706,9 @@ load_file_and_read_header (const gchar * path, gchar ** targetname,
 {
   GKeyFile *in;
   gboolean res;
+  GError *key_error = NULL;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
   in = g_key_file_new ();
 
@@ -651,12 +716,13 @@ load_file_and_read_header (const gchar * path, gchar ** targetname,
 
   res =
       g_key_file_load_from_file (in, path,
-      G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, error);
-  if (!res || error != NULL)
+      G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &key_error);
+  if (!res || key_error != NULL)
     goto load_error;
 
+  key_error = NULL;
   *targetname =
-      g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", error);
+      g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", &key_error);
   if (!*targetname)
     goto empty_name;
 
@@ -671,22 +737,24 @@ load_file_and_read_header (const gchar * path, gchar ** targetname,
 load_error:
   {
     GST_WARNING ("Unable to read GstEncodingTarget file %s: %s",
-        path, (*error)->message);
+        path, key_error->message);
+    g_propagate_error (error, key_error);
     g_key_file_free (in);
     return NULL;
   }
 
 empty_name:
   {
-    GST_WARNING ("Wrong header in file %s: %s", path, (*error)->message);
+    GST_WARNING ("Wrong header in file %s: %s", path, key_error->message);
+    g_propagate_error (error, key_error);
     g_key_file_free (in);
     return NULL;
   }
 }
 
 /**
- * gst_encoding_target_load_from:
- * @path: The file to load the #GstEncodingTarget from
+ * gst_encoding_target_load_from_file:
+ * @filepath: The file location to load the #GstEncodingTarget from
  * @error: If an error occured, this field will be filled in.
  *
  * Opens the provided file and returns the contained #GstEncodingTarget.
@@ -698,13 +766,13 @@ empty_name:
  */
 
 GstEncodingTarget *
-gst_encoding_target_load_from (const gchar * path, GError ** error)
+gst_encoding_target_load_from_file (const gchar * filepath, GError ** error)
 {
   GKeyFile *in;
   gchar *targetname, *categoryname, *description;
   GstEncodingTarget *res = NULL;
 
-  in = load_file_and_read_header (path, &targetname, &categoryname,
+  in = load_file_and_read_header (filepath, &targetname, &categoryname,
       &description, error);
   if (!in)
     goto beach;
@@ -717,8 +785,7 @@ beach:
   return res;
 }
 
-/**
- *
+/*
  * returned list contents must be freed
  */
 static GList *
@@ -761,14 +828,14 @@ gst_encoding_target_subload (gchar * path, const gchar * category,
     gchar *filename;
 
     filename = g_build_filename (path, category, lfilename, NULL);
-    target = gst_encoding_target_load_from (filename, error);
+    target = gst_encoding_target_load_from_file (filename, error);
     g_free (filename);
   } else {
     GList *tmp, *tries = get_matching_filenames (path, lfilename);
 
     /* Try to find a file named %s.gstprofile in any subdirectories */
     for (tmp = tries; tmp; tmp = tmp->next) {
-      target = gst_encoding_target_load_from ((gchar *) tmp->data, NULL);
+      target = gst_encoding_target_load_from_file ((gchar *) tmp->data, NULL);
       if (target)
         break;
     }
@@ -783,7 +850,8 @@ gst_encoding_target_subload (gchar * path, const gchar * category,
 /**
  * gst_encoding_target_load:
  * @name: the name of the #GstEncodingTarget to load.
- * @category: (allow-none): the name of the target category. Can be %NULL
+ * @category: (allow-none): the name of the target category, like
+ * #GST_ENCODING_CATEGORY_DEVICE. Can be %NULL
  * @error: If an error occured, this field will be filled in.
  *
  * Searches for the #GstEncodingTarget with the given name, loads it
@@ -811,12 +879,12 @@ gst_encoding_target_load (const gchar * name, const gchar * category,
   if (category && !validate_name (category))
     goto invalid_category;
 
-  lfilename = g_strdup_printf ("%s.gstprofile", name);
+  lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, name);
 
   /* Try from local profiles */
   tldir =
-      g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
-      "encoding-profile", NULL);
+      g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+      GST_ENCODING_TARGET_DIRECTORY, NULL);
   target = gst_encoding_target_subload (tldir, category, lfilename, error);
   g_free (tldir);
 
@@ -824,7 +892,7 @@ gst_encoding_target_load (const gchar * name, const gchar * category,
     /* Try from system-wide profiles */
     tldir =
         g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
-        "encoding-profile", NULL);
+        GST_ENCODING_TARGET_DIRECTORY, NULL);
     target = gst_encoding_target_subload (tldir, category, lfilename, error);
     g_free (tldir);
   }
@@ -846,12 +914,12 @@ invalid_category:
 }
 
 /**
- * gst_encoding_target_save_to:
+ * gst_encoding_target_save_to_file:
  * @target: a #GstEncodingTarget
- * @path: the location to store the @target at.
+ * @filepath: the location to store the @target at.
  * @error: If an error occured, this field will be filled in.
  *
- * Saves the @target to the provided location.
+ * Saves the @target to the provided file location.
  *
  * Since: 0.10.32
  *
@@ -859,17 +927,17 @@ invalid_category:
  **/
 
 gboolean
-gst_encoding_target_save_to (GstEncodingTarget * target, const gchar * path,
-    GError ** error)
+gst_encoding_target_save_to_file (GstEncodingTarget * target,
+    const gchar * filepath, GError ** error)
 {
   GKeyFile *out;
   gchar *data;
   gsize data_size;
 
   g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
-  g_return_val_if_fail (path != NULL, FALSE);
+  g_return_val_if_fail (filepath != NULL, FALSE);
 
-  /* FIXME : Check path is valid and writable
+  /* FIXME : Check filepath is valid and writable
    * FIXME : Strip out profiles already present in system target */
 
   /* Get unique name... */
@@ -883,7 +951,7 @@ gst_encoding_target_save_to (GstEncodingTarget * target, const gchar * path,
   if (!(data = g_key_file_to_data (out, &data_size, error)))
     goto convert_failed;
 
-  if (!g_file_set_contents (path, data, data_size, error))
+  if (!g_file_set_contents (filepath, data, data_size, error))
     goto write_failed;
 
   g_key_file_free (out);
@@ -908,7 +976,7 @@ convert_failed:
 
 write_failed:
   {
-    GST_ERROR ("Unable to write file %s: %s", path, (*error)->message);
+    GST_ERROR ("Unable to write file %s: %s", filepath, (*error)->message);
     g_key_file_free (out);
     g_free (data);
     return FALSE;
@@ -920,9 +988,7 @@ write_failed:
  * @target: a #GstEncodingTarget
  * @error: If an error occured, this field will be filled in.
  *
- * Saves the @target to the default location. Unless the user has write access
- * to the system-wide encoding target directory, it will be saved in a
- * user-local directory.
+ * Saves the @target to a default user-local directory.
  *
  * Since: 0.10.32
  *
@@ -934,18 +1000,17 @@ gst_encoding_target_save (GstEncodingTarget * target, GError ** error)
 {
   gchar *filename;
   gchar *lfilename;
-  gboolean res;
 
   g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
   g_return_val_if_fail (target->category != NULL, FALSE);
 
-  lfilename = g_strdup_printf ("%s.gstprofile", target->name);
+  lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, target->name);
   filename =
-      g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
-      "encoding-profile", target->category, lfilename, NULL);
+      g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+      GST_ENCODING_TARGET_DIRECTORY, target->category, lfilename, NULL);
   g_free (lfilename);
 
-  res = gst_encoding_target_save_to (target, filename, error);
+  gst_encoding_target_save_to_file (target, filename, error);
   g_free (filename);
 
   return TRUE;
@@ -983,7 +1048,9 @@ get_categories (gchar * path)
  *
  * Returns: (transfer full) (element-type gchar*): A list
  * of #GstEncodingTarget categories.
-*/
+ *
+ * Since: 0.10.32
+ */
 GList *
 gst_encoding_list_available_categories (void)
 {
@@ -992,14 +1059,14 @@ gst_encoding_list_available_categories (void)
   gchar *topdir;
 
   /* First try user-local categories */
-  topdir = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
-      "encoding-profile", NULL);
+  topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+      GST_ENCODING_TARGET_DIRECTORY, NULL);
   res = get_categories (topdir);
   g_free (topdir);
 
   /* Extend with system-wide categories */
   topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
-      "encoding-profile", NULL);
+      GST_ENCODING_TARGET_DIRECTORY, NULL);
   tmp1 = get_categories (topdir);
   g_free (topdir);
 
@@ -1031,11 +1098,11 @@ sub_get_all_targets (gchar * subdir)
     gchar *fullname;
 
     /* Only try files ending with .gstprofile */
-    if (!g_str_has_suffix (filename, ".gstprofile"))
+    if (!g_str_has_suffix (filename, GST_ENCODING_TARGET_SUFFIX))
       continue;
 
     fullname = g_build_filename (subdir, filename, NULL);
-    target = gst_encoding_target_load_from (fullname, NULL);
+    target = gst_encoding_target_load_from_file (fullname, NULL);
     if (target) {
       res = g_list_append (res, target);
     } else
@@ -1091,12 +1158,14 @@ compare_targets (const GstEncodingTarget * ta, const GstEncodingTarget * tb)
 /**
  * gst_encoding_list_all_targets:
  * @categoryname: (allow-none): The category, for ex: #GST_ENCODING_CATEGORY_DEVICE.
- * Can be NULL.
+ * Can be %NULL.
  *
  * List all available #GstEncodingTarget for the specified category, or all categories
- * if @categoryname is NULL.
+ * if @categoryname is %NULL.
  *
  * Returns: (transfer full) (element-type GstEncodingTarget): The list of #GstEncodingTarget
+ *
+ * Since: 0.10.32
  */
 GList *
 gst_encoding_list_all_targets (const gchar * categoryname)
@@ -1106,14 +1175,14 @@ gst_encoding_list_all_targets (const gchar * categoryname)
   gchar *topdir;
 
   /* Get user-locals */
-  topdir = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
-      "encoding-profile", NULL);
+  topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+      GST_ENCODING_TARGET_DIRECTORY, NULL);
   res = get_all_targets (topdir, categoryname);
   g_free (topdir);
 
   /* Get system-wide */
   topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
-      "encoding-profile", NULL);
+      GST_ENCODING_TARGET_DIRECTORY, NULL);
   tmp1 = get_all_targets (topdir, categoryname);
   g_free (topdir);