1 /* GStreamer encoding profile registry
2 * Copyright (C) 2010 Edward Hervey <edward.hervey@collabora.co.uk>
3 * (C) 2010 Nokia Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
28 #include "encoding-target.h"
35 * [GStreamer Encoding Target]
37 * category : <category>
38 * description : <description> #translatable
40 * [profile-<profile1name>]
42 * description : <description> #optional
46 * [streamprofile-<id>]
47 * parent : <encodingprofile.name>[,<encodingprofile.name>..]
48 * type : <type> # "audio", "video", "text"
51 * restriction : <restriction>
52 * presence : <presence>
54 * variableframerate : <variableframerate>
58 * Location of profile files
60 * $GST_DATADIR/gstreamer-GST_API_VERSION/encoding-profile
61 * $HOME/gstreamer-GST_API_VERSION/encoding-profile
63 * There also is a GST_ENCODING_TARGET_PATH environment variable
64 * defining a list of folder containing encoding target files.
67 * $(target.category)/$(target.name).gep
69 * Naming restrictions:
70 * lowercase ASCII letter for the first character
71 * Same for all other characters + numerics + hyphens
75 #define GST_ENCODING_TARGET_HEADER "GStreamer Encoding Target"
76 #define GST_ENCODING_TARGET_DIRECTORY "encoding-profiles"
77 #define GST_ENCODING_TARGET_SUFFIX ".gep"
79 struct _GstEncodingTarget
92 G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, G_TYPE_OBJECT);
95 gst_encoding_target_init (GstEncodingTarget * target)
97 /* Nothing to initialize */
101 gst_encoding_target_finalize (GObject * object)
103 GstEncodingTarget *target = (GstEncodingTarget *) object;
105 GST_DEBUG ("Finalizing");
108 g_free (target->name);
109 if (target->category)
110 g_free (target->category);
111 if (target->description)
112 g_free (target->description);
114 g_list_foreach (target->profiles, (GFunc) g_object_unref, NULL);
115 g_list_free (target->profiles);
119 gst_encoding_target_class_init (GObjectClass * klass)
121 klass->finalize = gst_encoding_target_finalize;
125 * gst_encoding_target_get_name:
126 * @target: a #GstEncodingTarget
128 * Returns: (transfer none): The name of the @target.
131 gst_encoding_target_get_name (GstEncodingTarget * target)
137 * gst_encoding_target_get_category:
138 * @target: a #GstEncodingTarget
140 * Returns: (transfer none): The category of the @target. For example:
141 * #GST_ENCODING_CATEGORY_DEVICE.
144 gst_encoding_target_get_category (GstEncodingTarget * target)
146 return target->category;
150 * gst_encoding_target_get_description:
151 * @target: a #GstEncodingTarget
153 * Returns: (transfer none): The description of the @target.
156 gst_encoding_target_get_description (GstEncodingTarget * target)
158 return target->description;
162 * gst_encoding_target_get_profiles:
163 * @target: a #GstEncodingTarget
165 * Returns: (transfer none) (element-type GstPbutils.EncodingProfile): A list of
166 * #GstEncodingProfile(s) this @target handles.
169 gst_encoding_target_get_profiles (GstEncodingTarget * target)
171 return target->profiles;
175 * gst_encoding_target_get_profile:
176 * @target: a #GstEncodingTarget
177 * @name: the name of the profile to retrieve
179 * Returns: (transfer full): The matching #GstEncodingProfile, or %NULL.
182 gst_encoding_target_get_profile (GstEncodingTarget * target, const gchar * name)
186 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), NULL);
187 g_return_val_if_fail (name != NULL, NULL);
189 for (tmp = target->profiles; tmp; tmp = tmp->next) {
190 GstEncodingProfile *tprof = (GstEncodingProfile *) tmp->data;
192 if (!g_strcmp0 (gst_encoding_profile_get_name (tprof), name)) {
193 gst_encoding_profile_ref (tprof);
201 static inline gboolean
202 validate_name (const gchar * name)
210 /* First character can only be a lower case ASCII character */
211 if (!g_ascii_isalpha (name[0]) || !g_ascii_islower (name[0]))
214 /* All following characters can only by:
215 * either a lower case ASCII character
218 for (i = 1; i < len; i++) {
219 /* if uppercase ASCII letter, return */
220 if (g_ascii_isupper (name[i]))
222 /* if a digit, continue */
223 if (g_ascii_isdigit (name[i]))
225 /* if an hyphen, continue */
228 /* remaining should only be ascii letters */
229 if (!g_ascii_isalpha (name[i]))
237 * gst_encoding_target_new:
238 * @name: The name of the target.
239 * @category: (transfer none): The name of the category to which this @target
240 * belongs. For example: #GST_ENCODING_CATEGORY_DEVICE.
241 * @description: (transfer none): A description of #GstEncodingTarget in the
243 * @profiles: (transfer none) (element-type GstPbutils.EncodingProfile): A #GList of
244 * #GstEncodingProfile.
246 * Creates a new #GstEncodingTarget.
248 * The name and category can only consist of lowercase ASCII letters for the
249 * first character, followed by either lowercase ASCII letters, digits or
252 * The @category <emphasis>should</emphasis> be one of the existing
253 * well-defined categories, like #GST_ENCODING_CATEGORY_DEVICE, but it
254 * <emphasis>can</emphasis> be a application or user specific category if
257 * Returns: (transfer full): The newly created #GstEncodingTarget or %NULL if
258 * there was an error.
262 gst_encoding_target_new (const gchar * name, const gchar * category,
263 const gchar * description, const GList * profiles)
265 GstEncodingTarget *res;
267 g_return_val_if_fail (name != NULL, NULL);
268 g_return_val_if_fail (category != NULL, NULL);
269 g_return_val_if_fail (description != NULL, NULL);
272 if (!validate_name (name))
274 if (category && !validate_name (category))
275 goto invalid_category;
277 res = (GstEncodingTarget *) g_object_new (GST_TYPE_ENCODING_TARGET, NULL);
278 res->name = g_strdup (name);
279 res->category = g_strdup (category);
280 res->description = g_strdup (description);
283 GstEncodingProfile *prof = (GstEncodingProfile *) profiles->data;
286 g_list_append (res->profiles, gst_encoding_profile_ref (prof));
287 profiles = profiles->next;
294 GST_ERROR ("Invalid name for encoding target : '%s'", name);
300 GST_ERROR ("Invalid name for encoding category : '%s'", category);
306 * gst_encoding_target_add_profile:
307 * @target: the #GstEncodingTarget to add a profile to
308 * @profile: (transfer full): the #GstEncodingProfile to add
310 * Adds the given @profile to the @target. Each added profile must have
311 * a unique name within the profile.
313 * The @target will steal a reference to the @profile. If you wish to use
314 * the profile after calling this method, you should increase its reference
317 * Returns: %TRUE if the profile was added, else %FALSE.
321 gst_encoding_target_add_profile (GstEncodingTarget * target,
322 GstEncodingProfile * profile)
326 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
327 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
329 /* Make sure profile isn't already controlled by this target */
330 for (tmp = target->profiles; tmp; tmp = tmp->next) {
331 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
333 if (!g_strcmp0 (gst_encoding_profile_get_name (profile),
334 gst_encoding_profile_get_name (prof))) {
335 GST_WARNING ("Profile already present in target");
340 target->profiles = g_list_append (target->profiles, profile);
346 serialize_stream_profiles (GKeyFile * out, GstEncodingProfile * sprof,
347 const gchar * profilename, guint id)
349 gchar *sprofgroupname;
351 GstCaps *format, *restriction;
352 const gchar *preset, *name, *description;
354 sprofgroupname = g_strdup_printf ("streamprofile-%s-%d", profilename, id);
356 /* Write the parent profile */
357 g_key_file_set_value (out, sprofgroupname, "parent", profilename);
359 g_key_file_set_value (out, sprofgroupname, "type",
360 gst_encoding_profile_get_type_nick (sprof));
362 format = gst_encoding_profile_get_format (sprof);
364 tmpc = gst_caps_to_string (format);
365 g_key_file_set_value (out, sprofgroupname, "format", tmpc);
369 name = gst_encoding_profile_get_name (sprof);
371 g_key_file_set_string (out, sprofgroupname, "name", name);
373 description = gst_encoding_profile_get_description (sprof);
375 g_key_file_set_string (out, sprofgroupname, "description", description);
377 preset = gst_encoding_profile_get_preset (sprof);
379 g_key_file_set_string (out, sprofgroupname, "preset", preset);
381 restriction = gst_encoding_profile_get_restriction (sprof);
383 tmpc = gst_caps_to_string (restriction);
384 g_key_file_set_value (out, sprofgroupname, "restriction", tmpc);
387 g_key_file_set_integer (out, sprofgroupname, "presence",
388 gst_encoding_profile_get_presence (sprof));
390 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
391 GstEncodingVideoProfile *vp = (GstEncodingVideoProfile *) sprof;
393 g_key_file_set_integer (out, sprofgroupname, "pass",
394 gst_encoding_video_profile_get_pass (vp));
395 g_key_file_set_boolean (out, sprofgroupname, "variableframerate",
396 gst_encoding_video_profile_get_variableframerate (vp));
399 g_free (sprofgroupname);
401 gst_caps_unref (format);
403 gst_caps_unref (restriction);
410 const char *loc = NULL;
414 #if defined(LC_MESSAGES)
415 loc = setlocale (LC_MESSAGES, NULL);
416 GST_LOG ("LC_MESSAGES: %s", GST_STR_NULL (loc));
417 #elif defined(LC_ALL)
418 loc = setlocale (LC_ALL, NULL);
419 GST_LOG ("LC_ALL: %s", GST_STR_NULL (loc));
421 GST_LOG ("Neither LC_ALL nor LC_MESSAGES defined");
423 #else /* !ENABLE_NLS */
424 GST_LOG ("i18n disabled");
427 if (loc == NULL || g_ascii_strncasecmp (loc, "en", 2) == 0)
430 /* en_GB.UTF-8 => en */
431 ret = g_ascii_strdown (loc, -1);
432 ret = g_strcanon (ret, "abcdefghijklmnopqrstuvwxyz", '\0');
433 GST_LOG ("using locale: %s", ret);
437 /* Serialize the top-level profiles
438 * Note: They don't have to be containerprofiles */
440 serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof)
442 gchar *profgroupname;
445 const gchar *profname, *profdesc, *profpreset, *proftype;
448 profname = gst_encoding_profile_get_name (prof);
449 profdesc = gst_encoding_profile_get_description (prof);
450 profformat = gst_encoding_profile_get_format (prof);
451 profpreset = gst_encoding_profile_get_preset (prof);
452 proftype = gst_encoding_profile_get_type_nick (prof);
454 profgroupname = g_strdup_printf ("profile-%s", profname);
456 g_key_file_set_string (out, profgroupname, "name", profname);
458 g_key_file_set_value (out, profgroupname, "type", proftype);
463 locale = get_locale ();
464 if (locale != NULL) {
465 g_key_file_set_locale_string (out, profgroupname, "description",
469 g_key_file_set_string (out, profgroupname, "description", profdesc);
473 gchar *tmpc = gst_caps_to_string (profformat);
474 g_key_file_set_string (out, profgroupname, "format", tmpc);
478 g_key_file_set_string (out, profgroupname, "preset", profpreset);
480 /* stream profiles */
481 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
483 gst_encoding_container_profile_get_profiles
484 (GST_ENCODING_CONTAINER_PROFILE (prof)), i = 0; tmp;
485 tmp = tmp->next, i++) {
486 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
488 if (!serialize_stream_profiles (out, sprof, profname, i))
493 gst_caps_unref (profformat);
494 g_free (profgroupname);
499 serialize_target (GKeyFile * out, GstEncodingTarget * target)
503 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "name", target->name);
504 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "category",
506 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "description",
507 target->description);
509 for (tmp = target->profiles; tmp; tmp = tmp->next) {
510 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
511 if (!serialize_encoding_profile (out, prof))
519 * parse_encoding_profile:
521 * @parentprofilename: the parent profile name (including 'profile-' or 'streamprofile-' header)
522 * @profilename: the profile name group to parse
523 * @nbgroups: the number of top-level groups
524 * @groups: the top-level groups
526 static GstEncodingProfile *
527 parse_encoding_profile (GKeyFile * in, gchar * parentprofilename,
528 gchar * profilename, gsize nbgroups, gchar ** groups)
530 GstEncodingProfile *sprof = NULL;
532 gchar *proftype, *format, *preset, *restriction, *pname, *description;
533 GstCaps *formatcaps = NULL;
534 GstCaps *restrictioncaps = NULL;
535 gboolean variableframerate;
537 gsize i, nbencprofiles;
539 GST_DEBUG ("parentprofilename : %s , profilename : %s",
540 parentprofilename, profilename);
542 if (parentprofilename) {
543 gboolean found = FALSE;
546 g_key_file_get_string_list (in, profilename, "parent",
547 &nbencprofiles, NULL);
548 if (!parent || !nbencprofiles) {
552 /* Check if this streamprofile is used in <profilename> */
553 for (i = 0; i < nbencprofiles; i++) {
554 if (!g_strcmp0 (parent[i], parentprofilename)) {
562 GST_DEBUG ("Stream profile '%s' isn't used in profile '%s'",
563 profilename, parentprofilename);
568 pname = g_key_file_get_value (in, profilename, "name", NULL);
570 /* First try to get localized description */
574 locale = get_locale ();
575 if (locale != NULL) {
576 /* will try to fall back to untranslated string if no translation found */
577 description = g_key_file_get_locale_string (in, profilename,
578 "description", locale, NULL);
582 g_key_file_get_string (in, profilename, "description", NULL);
586 /* Note: a missing description is normal for non-container profiles */
587 if (description == NULL) {
588 GST_LOG ("Missing 'description' field for streamprofile %s", profilename);
591 /* Parse the remaining fields */
592 proftype = g_key_file_get_value (in, profilename, "type", NULL);
594 GST_WARNING ("Missing 'type' field for streamprofile %s", profilename);
598 format = g_key_file_get_value (in, profilename, "format", NULL);
600 formatcaps = gst_caps_from_string (format);
604 preset = g_key_file_get_value (in, profilename, "preset", NULL);
606 restriction = g_key_file_get_value (in, profilename, "restriction", NULL);
608 restrictioncaps = gst_caps_from_string (restriction);
609 g_free (restriction);
612 presence = g_key_file_get_integer (in, profilename, "presence", NULL);
613 pass = g_key_file_get_integer (in, profilename, "pass", NULL);
615 g_key_file_get_boolean (in, profilename, "variableframerate", NULL);
617 /* Build the streamprofile ! */
618 if (!g_strcmp0 (proftype, "container")) {
619 GstEncodingProfile *pprof;
622 (GstEncodingProfile *) gst_encoding_container_profile_new (pname,
623 description, formatcaps, preset);
624 /* Now look for the stream profiles */
625 for (i = 0; i < nbgroups; i++) {
626 if (!g_ascii_strncasecmp (groups[i], "streamprofile-", 13)) {
627 pprof = parse_encoding_profile (in, pname, groups[i], nbgroups, groups);
629 gst_encoding_container_profile_add_profile (
630 (GstEncodingContainerProfile *) sprof, pprof);
634 } else if (!g_strcmp0 (proftype, "video")) {
636 (GstEncodingProfile *) gst_encoding_video_profile_new (formatcaps,
637 preset, restrictioncaps, presence);
638 gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile
639 *) sprof, variableframerate);
640 gst_encoding_video_profile_set_pass ((GstEncodingVideoProfile *) sprof,
642 gst_encoding_profile_set_name (sprof, pname);
643 gst_encoding_profile_set_description (sprof, description);
644 } else if (!g_strcmp0 (proftype, "audio")) {
646 (GstEncodingProfile *) gst_encoding_audio_profile_new (formatcaps,
647 preset, restrictioncaps, presence);
648 gst_encoding_profile_set_name (sprof, pname);
649 gst_encoding_profile_set_description (sprof, description);
651 GST_ERROR ("Unknown profile format '%s'", proftype);
654 gst_caps_unref (restrictioncaps);
656 gst_caps_unref (formatcaps);
661 g_free (description);
670 static GstEncodingTarget *
671 parse_keyfile (GKeyFile * in, gchar * targetname, gchar * categoryname,
674 GstEncodingTarget *res = NULL;
675 GstEncodingProfile *prof;
679 res = gst_encoding_target_new (targetname, categoryname, description, NULL);
681 /* Figure out the various profiles */
682 groups = g_key_file_get_groups (in, &nbgroups);
683 for (i = 0; i < nbgroups; i++) {
684 if (!g_ascii_strncasecmp (groups[i], "profile-", 8)) {
685 prof = parse_encoding_profile (in, NULL, groups[i], nbgroups, groups);
687 gst_encoding_target_add_profile (res, prof);
696 g_free (categoryname);
698 g_free (description);
704 load_file_and_read_header (const gchar * path, gchar ** targetname,
705 gchar ** categoryname, gchar ** description, GError ** error)
709 GError *key_error = NULL;
711 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
713 in = g_key_file_new ();
715 GST_DEBUG ("path:%s", path);
718 g_key_file_load_from_file (in, path,
719 G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &key_error);
720 if (!res || key_error != NULL)
725 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", &key_error);
730 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "category", NULL);
732 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "description",
739 GST_WARNING ("Unable to read GstEncodingTarget file %s: %s",
740 path, key_error->message);
741 g_propagate_error (error, key_error);
742 g_key_file_free (in);
748 GST_WARNING ("Wrong header in file %s: %s", path, key_error->message);
749 g_propagate_error (error, key_error);
750 g_key_file_free (in);
756 * gst_encoding_target_load_from_file:
757 * @filepath: The file location to load the #GstEncodingTarget from
758 * @error: If an error occured, this field will be filled in.
760 * Opens the provided file and returns the contained #GstEncodingTarget.
762 * Returns: (transfer full): The #GstEncodingTarget contained in the file, else
767 gst_encoding_target_load_from_file (const gchar * filepath, GError ** error)
770 gchar *targetname, *categoryname, *description;
771 GstEncodingTarget *res = NULL;
773 in = load_file_and_read_header (filepath, &targetname, &categoryname,
774 &description, error);
778 res = parse_keyfile (in, targetname, categoryname, description);
780 g_key_file_free (in);
787 * returned list contents must be freed
790 get_matching_filenames (gchar * path, gchar * filename)
794 const gchar *subdirname;
797 topdir = g_dir_open (path, 0, NULL);
798 if (G_UNLIKELY (topdir == NULL))
801 tmp = g_build_filename (path, filename, NULL);
802 if (g_file_test (tmp, G_FILE_TEST_EXISTS))
803 res = g_list_append (res, tmp);
805 while ((subdirname = g_dir_read_name (topdir))) {
806 gchar *ltmp = g_build_filename (path, subdirname, NULL);
808 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
809 gchar *tmp = g_build_filename (path, subdirname, filename, NULL);
810 /* Test to see if we have a file named like that in that directory */
811 if (g_file_test (tmp, G_FILE_TEST_EXISTS))
812 res = g_list_append (res, tmp);
819 g_dir_close (topdir);
824 static GstEncodingTarget *
825 gst_encoding_target_subload (gchar * path, const gchar * category,
826 gchar * lfilename, GError ** error)
828 GstEncodingTarget *target = NULL;
833 filename = g_build_filename (path, category, lfilename, NULL);
834 target = gst_encoding_target_load_from_file (filename, error);
837 GList *tmp, *tries = get_matching_filenames (path, lfilename);
839 /* Try to find a file named %s.gstprofile in any subdirectories */
840 for (tmp = tries; tmp; tmp = tmp->next) {
841 target = gst_encoding_target_load_from_file ((gchar *) tmp->data, NULL);
845 g_list_foreach (tries, (GFunc) g_free, NULL);
854 * gst_encoding_target_load:
855 * @name: the name of the #GstEncodingTarget to load.
856 * @category: (allow-none): the name of the target category, like
857 * #GST_ENCODING_CATEGORY_DEVICE. Can be %NULL
858 * @error: If an error occured, this field will be filled in.
860 * Searches for the #GstEncodingTarget with the given name, loads it
863 * If the category name is specified only targets from that category will be
866 * Returns: (transfer full): The #GstEncodingTarget if available, else %NULL.
869 gst_encoding_target_load (const gchar * name, const gchar * category,
873 gchar *lfilename, *tldir, **encoding_target_dirs;
875 GstEncodingTarget *target = NULL;
877 g_return_val_if_fail (name != NULL, NULL);
879 if (!validate_name (name))
882 if (category && !validate_name (category))
883 goto invalid_category;
885 lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, name);
887 envvar = g_getenv ("GST_ENCODING_TARGET_PATH");
889 encoding_target_dirs = g_strsplit (envvar, G_SEARCHPATH_SEPARATOR_S, -1);
890 for (i = 0; encoding_target_dirs[i]; i++) {
891 target = gst_encoding_target_subload (encoding_target_dirs[i],
892 category, lfilename, error);
895 g_strfreev (encoding_target_dirs);
900 /* Try from local profiles */
903 g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION,
904 GST_ENCODING_TARGET_DIRECTORY, NULL);
905 target = gst_encoding_target_subload (tldir, category, lfilename, error);
908 if (target == NULL) {
909 /* Try from system-wide profiles */
911 g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION,
912 GST_ENCODING_TARGET_DIRECTORY, NULL);
913 target = gst_encoding_target_subload (tldir, category, lfilename, error);
924 GST_ERROR ("Invalid name for encoding target : '%s'", name);
929 GST_ERROR ("Invalid name for encoding category : '%s'", category);
935 * gst_encoding_target_save_to_file:
936 * @target: a #GstEncodingTarget
937 * @filepath: the location to store the @target at.
938 * @error: If an error occured, this field will be filled in.
940 * Saves the @target to the provided file location.
942 * Returns: %TRUE if the target was correctly saved, else %FALSE.
946 gst_encoding_target_save_to_file (GstEncodingTarget * target,
947 const gchar * filepath, GError ** error)
953 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
954 g_return_val_if_fail (filepath != NULL, FALSE);
956 /* FIXME : Check filepath is valid and writable
957 * FIXME : Strip out profiles already present in system target */
959 /* Get unique name... */
961 /* Create output GKeyFile */
962 out = g_key_file_new ();
964 if (!serialize_target (out, target))
965 goto serialize_failure;
967 if (!(data = g_key_file_to_data (out, &data_size, error)))
970 if (!g_file_set_contents (filepath, data, data_size, error))
973 g_key_file_free (out);
980 GST_ERROR ("Failure serializing target");
981 g_key_file_free (out);
987 GST_ERROR ("Failure converting keyfile: %s", (*error)->message);
988 g_key_file_free (out);
995 GST_ERROR ("Unable to write file %s: %s", filepath, (*error)->message);
996 g_key_file_free (out);
1003 * gst_encoding_target_save:
1004 * @target: a #GstEncodingTarget
1005 * @error: If an error occured, this field will be filled in.
1007 * Saves the @target to a default user-local directory.
1009 * Returns: %TRUE if the target was correctly saved, else %FALSE.
1013 gst_encoding_target_save (GstEncodingTarget * target, GError ** error)
1019 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
1020 g_return_val_if_fail (target->category != NULL, FALSE);
1022 lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, target->name);
1024 g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION,
1025 GST_ENCODING_TARGET_DIRECTORY, target->category, NULL);
1027 if (g_mkdir_with_parents (dirname, 0755)) {
1028 GST_ERROR_OBJECT (target, "Could not create directory to save %s into: %s",
1029 target->name, g_strerror (errno));
1033 filename = g_build_filename (dirname, lfilename, NULL);
1037 gst_encoding_target_save_to_file (target, filename, error);
1044 get_categories (gchar * path)
1048 const gchar *subdirname;
1050 topdir = g_dir_open (path, 0, NULL);
1051 if (G_UNLIKELY (topdir == NULL))
1054 while ((subdirname = g_dir_read_name (topdir))) {
1055 gchar *ltmp = g_build_filename (path, subdirname, NULL);
1057 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
1058 res = g_list_append (res, (gpointer) g_strdup (subdirname));
1063 g_dir_close (topdir);
1069 * gst_encoding_list_available_categories:
1071 * Lists all #GstEncodingTarget categories present on disk.
1073 * Returns: (transfer full) (element-type gchar*): A list
1074 * of #GstEncodingTarget categories.
1077 gst_encoding_list_available_categories (void)
1083 /* First try user-local categories */
1085 g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION,
1086 GST_ENCODING_TARGET_DIRECTORY, NULL);
1087 res = get_categories (topdir);
1090 /* Extend with system-wide categories */
1091 topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION,
1092 GST_ENCODING_TARGET_DIRECTORY, NULL);
1093 tmp1 = get_categories (topdir);
1096 for (tmp2 = tmp1; tmp2; tmp2 = tmp2->next) {
1097 gchar *name = (gchar *) tmp2->data;
1098 if (!g_list_find_custom (res, name, (GCompareFunc) g_strcmp0))
1099 res = g_list_append (res, (gpointer) name);
1108 static inline GList *
1109 sub_get_all_targets (gchar * subdir)
1112 const gchar *filename;
1114 GstEncodingTarget *target;
1116 dir = g_dir_open (subdir, 0, NULL);
1117 if (G_UNLIKELY (dir == NULL))
1120 while ((filename = g_dir_read_name (dir))) {
1123 /* Only try files ending with .gstprofile */
1124 if (!g_str_has_suffix (filename, GST_ENCODING_TARGET_SUFFIX))
1127 fullname = g_build_filename (subdir, filename, NULL);
1128 target = gst_encoding_target_load_from_file (fullname, NULL);
1130 res = g_list_append (res, target);
1132 GST_WARNING ("Failed to get a target from %s", fullname);
1140 static inline GList *
1141 get_all_targets (gchar * topdir, const gchar * categoryname)
1146 gchar *subdir = g_build_filename (topdir, categoryname, NULL);
1147 /* Try to open the directory */
1148 res = sub_get_all_targets (subdir);
1151 const gchar *subdirname;
1152 GDir *dir = g_dir_open (topdir, 0, NULL);
1154 if (G_UNLIKELY (dir == NULL))
1157 while ((subdirname = g_dir_read_name (dir))) {
1158 gchar *ltmp = g_build_filename (topdir, subdirname, NULL);
1160 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
1161 res = g_list_concat (res, sub_get_all_targets (ltmp));
1172 compare_targets (const GstEncodingTarget * ta, const GstEncodingTarget * tb)
1174 if (!g_strcmp0 (ta->name, tb->name)
1175 && !g_strcmp0 (ta->category, tb->category))
1182 * gst_encoding_list_all_targets:
1183 * @categoryname: (allow-none): The category, for ex: #GST_ENCODING_CATEGORY_DEVICE.
1186 * List all available #GstEncodingTarget for the specified category, or all categories
1187 * if @categoryname is %NULL.
1189 * Returns: (transfer full) (element-type GstEncodingTarget): The list of #GstEncodingTarget
1192 gst_encoding_list_all_targets (const gchar * categoryname)
1198 /* Get user-locals */
1200 g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION,
1201 GST_ENCODING_TARGET_DIRECTORY, NULL);
1202 res = get_all_targets (topdir, categoryname);
1205 /* Get system-wide */
1206 topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION,
1207 GST_ENCODING_TARGET_DIRECTORY, NULL);
1208 tmp1 = get_all_targets (topdir, categoryname);
1211 /* Merge system-wide targets */
1212 /* FIXME : We should merge the system-wide profiles into the user-locals
1213 * instead of stopping at identical target names */
1214 for (tmp2 = tmp1; tmp2; tmp2 = tmp2->next) {
1215 GstEncodingTarget *target = (GstEncodingTarget *) tmp2->data;
1216 if (g_list_find_custom (res, target, (GCompareFunc) compare_targets))
1217 gst_encoding_target_unref (target);
1219 res = g_list_append (res, target);