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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
27 #include "encoding-target.h"
34 * [GStreamer Encoding Target]
36 * category : <category>
37 * description : <description> #translatable
39 * [profile-<profile1name>]
41 * description : <description> #optional
45 * [streamprofile-<id>]
46 * parent : <encodingprofile.name>[,<encodingprofile.name>..]
47 * type : <type> # "audio", "video", "text"
50 * restriction : <restriction>
51 * presence : <presence>
53 * variableframerate : <variableframerate>
57 * Location of profile files
59 * $GST_DATADIR/gstreamer-GST_MAJORMINOR/encoding-profile
60 * $HOME/gstreamer-GST_MAJORMINOR/encoding-profile
63 * $(target.category)/$(target.name).gep
65 * Naming restrictions:
66 * lowercase ASCII letter for the first character
67 * Same for all other characters + numerics + hyphens
71 #define GST_ENCODING_TARGET_HEADER "GStreamer Encoding Target"
72 #define GST_ENCODING_TARGET_DIRECTORY "encoding-profiles"
73 #define GST_ENCODING_TARGET_SUFFIX ".gep"
75 struct _GstEncodingTarget
88 G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, GST_TYPE_MINI_OBJECT);
91 gst_encoding_target_init (GstEncodingTarget * target)
93 /* Nothing to initialize */
97 gst_encoding_target_finalize (GstEncodingTarget * target)
99 GST_DEBUG ("Finalizing");
102 g_free (target->name);
103 if (target->category)
104 g_free (target->category);
105 if (target->description)
106 g_free (target->description);
108 g_list_foreach (target->profiles, (GFunc) gst_mini_object_unref, NULL);
109 g_list_free (target->profiles);
113 gst_encoding_target_class_init (GstMiniObjectClass * klass)
116 (GstMiniObjectFinalizeFunction) gst_encoding_target_finalize;
120 * gst_encoding_target_get_name:
121 * @target: a #GstEncodingTarget
125 * Returns: (transfer none): The name of the @target.
128 gst_encoding_target_get_name (GstEncodingTarget * target)
134 * gst_encoding_target_get_category:
135 * @target: a #GstEncodingTarget
139 * Returns: (transfer none): The category of the @target. For example:
140 * #GST_ENCODING_CATEGORY_DEVICE.
143 gst_encoding_target_get_category (GstEncodingTarget * target)
145 return target->category;
149 * gst_encoding_target_get_description:
150 * @target: a #GstEncodingTarget
154 * Returns: (transfer none): The description of the @target.
157 gst_encoding_target_get_description (GstEncodingTarget * target)
159 return target->description;
163 * gst_encoding_target_get_profiles:
164 * @target: a #GstEncodingTarget
168 * Returns: (transfer none) (element-type Gst.EncodingProfile): A list of
169 * #GstEncodingProfile(s) this @target handles.
172 gst_encoding_target_get_profiles (GstEncodingTarget * target)
174 return target->profiles;
178 * gst_encoding_target_get_profile:
179 * @target: a #GstEncodingTarget
180 * @name: the name of the profile to retrieve
184 * Returns: (transfer full): The matching #GstEncodingProfile, or %NULL.
187 gst_encoding_target_get_profile (GstEncodingTarget * target, const gchar * name)
191 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), NULL);
192 g_return_val_if_fail (name != NULL, NULL);
194 for (tmp = target->profiles; tmp; tmp = tmp->next) {
195 GstEncodingProfile *tprof = (GstEncodingProfile *) tmp->data;
197 if (!g_strcmp0 (gst_encoding_profile_get_name (tprof), name)) {
198 gst_encoding_profile_ref (tprof);
206 static inline gboolean
207 validate_name (const gchar * name)
215 /* First character can only be a lower case ASCII character */
216 if (!g_ascii_isalpha (name[0]) || !g_ascii_islower (name[0]))
219 /* All following characters can only by:
220 * either a lower case ASCII character
223 for (i = 1; i < len; i++) {
224 /* if uppercase ASCII letter, return */
225 if (g_ascii_isupper (name[i]))
227 /* if a digit, continue */
228 if (g_ascii_isdigit (name[i]))
230 /* if an hyphen, continue */
233 /* remaining should only be ascii letters */
234 if (!g_ascii_isalpha (name[i]))
242 * gst_encoding_target_new:
243 * @name: The name of the target.
244 * @category: (transfer none): The name of the category to which this @target
245 * belongs. For example: #GST_ENCODING_CATEGORY_DEVICE.
246 * @description: (transfer none): A description of #GstEncodingTarget in the
248 * @profiles: (transfer none) (element-type Gst.EncodingProfile): A #GList of
249 * #GstEncodingProfile.
251 * Creates a new #GstEncodingTarget.
253 * The name and category can only consist of lowercase ASCII letters for the
254 * first character, followed by either lowercase ASCII letters, digits or
257 * The @category <emphasis>should</emphasis> be one of the existing
258 * well-defined categories, like #GST_ENCODING_CATEGORY_DEVICE, but it
259 * <emphasis>can</emphasis> be a application or user specific category if
264 * Returns: (transfer full): The newly created #GstEncodingTarget or %NULL if
265 * there was an error.
269 gst_encoding_target_new (const gchar * name, const gchar * category,
270 const gchar * description, const GList * profiles)
272 GstEncodingTarget *res;
274 g_return_val_if_fail (name != NULL, NULL);
275 g_return_val_if_fail (category != NULL, NULL);
276 g_return_val_if_fail (description != NULL, NULL);
279 if (!validate_name (name))
281 if (!validate_name (category))
282 goto invalid_category;
284 res = (GstEncodingTarget *) gst_mini_object_new (GST_TYPE_ENCODING_TARGET);
285 res->name = g_strdup (name);
286 res->category = g_strdup (category);
287 res->description = g_strdup (description);
290 GstEncodingProfile *prof = (GstEncodingProfile *) profiles->data;
293 g_list_append (res->profiles, gst_encoding_profile_ref (prof));
294 profiles = profiles->next;
301 GST_ERROR ("Invalid name for encoding target : '%s'", name);
307 GST_ERROR ("Invalid name for encoding category : '%s'", category);
313 * gst_encoding_target_add_profile:
314 * @target: the #GstEncodingTarget to add a profile to
315 * @profile: (transfer full): the #GstEncodingProfile to add
317 * Adds the given @profile to the @target. Each added profile must have
318 * a unique name within the profile.
320 * The @target will steal a reference to the @profile. If you wish to use
321 * the profile after calling this method, you should increase its reference
326 * Returns: %TRUE if the profile was added, else %FALSE.
330 gst_encoding_target_add_profile (GstEncodingTarget * target,
331 GstEncodingProfile * profile)
335 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
336 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
338 /* Make sure profile isn't already controlled by this target */
339 for (tmp = target->profiles; tmp; tmp = tmp->next) {
340 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
342 if (!g_strcmp0 (gst_encoding_profile_get_name (profile),
343 gst_encoding_profile_get_name (prof))) {
344 GST_WARNING ("Profile already present in target");
349 target->profiles = g_list_append (target->profiles, profile);
355 serialize_stream_profiles (GKeyFile * out, GstEncodingProfile * sprof,
356 const gchar * profilename, guint id)
358 gchar *sprofgroupname;
360 const GstCaps *format, *restriction;
361 const gchar *preset, *name, *description;
363 sprofgroupname = g_strdup_printf ("streamprofile-%s-%d", profilename, id);
365 /* Write the parent profile */
366 g_key_file_set_value (out, sprofgroupname, "parent", profilename);
368 g_key_file_set_value (out, sprofgroupname, "type",
369 gst_encoding_profile_get_type_nick (sprof));
371 format = gst_encoding_profile_get_format (sprof);
373 tmpc = gst_caps_to_string (format);
374 g_key_file_set_value (out, sprofgroupname, "format", tmpc);
378 name = gst_encoding_profile_get_name (sprof);
380 g_key_file_set_string (out, sprofgroupname, "name", name);
382 description = gst_encoding_profile_get_description (sprof);
384 g_key_file_set_string (out, sprofgroupname, "description", description);
386 preset = gst_encoding_profile_get_preset (sprof);
388 g_key_file_set_string (out, sprofgroupname, "preset", preset);
390 restriction = gst_encoding_profile_get_restriction (sprof);
392 tmpc = gst_caps_to_string (restriction);
393 g_key_file_set_value (out, sprofgroupname, "restriction", tmpc);
396 g_key_file_set_integer (out, sprofgroupname, "presence",
397 gst_encoding_profile_get_presence (sprof));
399 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
400 GstEncodingVideoProfile *vp = (GstEncodingVideoProfile *) sprof;
402 g_key_file_set_integer (out, sprofgroupname, "pass",
403 gst_encoding_video_profile_get_pass (vp));
404 g_key_file_set_boolean (out, sprofgroupname, "variableframerate",
405 gst_encoding_video_profile_get_variableframerate (vp));
408 g_free (sprofgroupname);
415 const char *loc = NULL;
419 #if defined(LC_MESSAGES)
420 loc = setlocale (LC_MESSAGES, NULL);
421 GST_LOG ("LC_MESSAGES: %s", GST_STR_NULL (loc));
422 #elif defined(LC_ALL)
423 loc = setlocale (LC_ALL, NULL);
424 GST_LOG ("LC_ALL: %s", GST_STR_NULL (loc));
426 GST_LOG ("Neither LC_ALL nor LC_MESSAGES defined");
428 #else /* !ENABLE_NLS */
429 GST_LOG ("i18n disabled");
432 if (loc == NULL || g_ascii_strncasecmp (loc, "en", 2) == 0)
435 /* en_GB.UTF-8 => en */
436 ret = g_ascii_strdown (loc, -1);
437 ret = g_strcanon (ret, "abcdefghijklmnopqrstuvwxyz", '\0');
438 GST_LOG ("using locale: %s", ret);
442 /* Serialize the top-level profiles
443 * Note: They don't have to be containerprofiles */
445 serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof)
447 gchar *profgroupname;
450 const gchar *profname, *profdesc, *profpreset, *proftype;
451 const GstCaps *profformat, *profrestriction;
453 profname = gst_encoding_profile_get_name (prof);
454 profdesc = gst_encoding_profile_get_description (prof);
455 profformat = gst_encoding_profile_get_format (prof);
456 profpreset = gst_encoding_profile_get_preset (prof);
457 proftype = gst_encoding_profile_get_type_nick (prof);
458 profrestriction = gst_encoding_profile_get_restriction (prof);
460 profgroupname = g_strdup_printf ("profile-%s", profname);
462 g_key_file_set_string (out, profgroupname, "name", profname);
464 g_key_file_set_value (out, profgroupname, "type",
465 gst_encoding_profile_get_type_nick (prof));
470 locale = get_locale ();
471 if (locale != NULL) {
472 g_key_file_set_locale_string (out, profgroupname, "description",
476 g_key_file_set_string (out, profgroupname, "description", profdesc);
480 gchar *tmpc = gst_caps_to_string (profformat);
481 g_key_file_set_string (out, profgroupname, "format", tmpc);
485 g_key_file_set_string (out, profgroupname, "preset", profpreset);
487 /* stream profiles */
488 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
490 gst_encoding_container_profile_get_profiles
491 (GST_ENCODING_CONTAINER_PROFILE (prof)), i = 0; tmp;
492 tmp = tmp->next, i++) {
493 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
495 if (!serialize_stream_profiles (out, sprof, profname, i))
499 g_free (profgroupname);
504 serialize_target (GKeyFile * out, GstEncodingTarget * target)
508 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "name", target->name);
509 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "category",
511 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "description",
512 target->description);
514 for (tmp = target->profiles; tmp; tmp = tmp->next) {
515 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
516 if (!serialize_encoding_profile (out, prof))
524 * parse_encoding_profile:
526 * @parentprofilename: the parent profile name (including 'profile-' or 'streamprofile-' header)
527 * @profilename: the profile name group to parse
528 * @nbgroups: the number of top-level groups
529 * @groups: the top-level groups
531 static GstEncodingProfile *
532 parse_encoding_profile (GKeyFile * in, gchar * parentprofilename,
533 gchar * profilename, gsize nbgroups, gchar ** groups)
535 GstEncodingProfile *sprof = NULL;
537 gchar *proftype, *format, *preset, *restriction, *pname, *description;
538 GstCaps *formatcaps = NULL;
539 GstCaps *restrictioncaps = NULL;
540 gboolean variableframerate;
542 gsize i, nbencprofiles;
544 GST_DEBUG ("parentprofilename : %s , profilename : %s",
545 parentprofilename, profilename);
547 if (parentprofilename) {
548 gboolean found = FALSE;
551 g_key_file_get_string_list (in, profilename, "parent",
552 &nbencprofiles, NULL);
553 if (!parent || !nbencprofiles) {
557 /* Check if this streamprofile is used in <profilename> */
558 for (i = 0; i < nbencprofiles; i++) {
559 if (!g_strcmp0 (parent[i], parentprofilename)) {
567 GST_DEBUG ("Stream profile '%s' isn't used in profile '%s'",
568 profilename, parentprofilename);
573 pname = g_key_file_get_value (in, profilename, "name", NULL);
575 /* First try to get localized description */
579 locale = get_locale ();
580 if (locale != NULL) {
581 /* will try to fall back to untranslated string if no translation found */
582 description = g_key_file_get_locale_string (in, profilename,
583 "description", locale, NULL);
587 g_key_file_get_string (in, profilename, "description", NULL);
591 /* Note: a missing description is normal for non-container profiles */
592 if (description == NULL) {
593 GST_LOG ("Missing 'description' field for streamprofile %s", profilename);
596 /* Parse the remaining fields */
597 proftype = g_key_file_get_value (in, profilename, "type", NULL);
599 GST_WARNING ("Missing 'type' field for streamprofile %s", profilename);
603 format = g_key_file_get_value (in, profilename, "format", NULL);
605 formatcaps = gst_caps_from_string (format);
609 preset = g_key_file_get_value (in, profilename, "preset", NULL);
611 restriction = g_key_file_get_value (in, profilename, "restriction", NULL);
613 restrictioncaps = gst_caps_from_string (restriction);
614 g_free (restriction);
617 presence = g_key_file_get_integer (in, profilename, "presence", NULL);
618 pass = g_key_file_get_integer (in, profilename, "pass", NULL);
620 g_key_file_get_boolean (in, profilename, "variableframerate", NULL);
622 /* Build the streamprofile ! */
623 if (!g_strcmp0 (proftype, "container")) {
624 GstEncodingProfile *pprof;
627 (GstEncodingProfile *) gst_encoding_container_profile_new (pname,
628 description, formatcaps, preset);
629 /* Now look for the stream profiles */
630 for (i = 0; i < nbgroups; i++) {
631 if (!g_ascii_strncasecmp (groups[i], "streamprofile-", 13)) {
632 pprof = parse_encoding_profile (in, pname, groups[i], nbgroups, groups);
634 gst_encoding_container_profile_add_profile (
635 (GstEncodingContainerProfile *) sprof, pprof);
639 } else if (!g_strcmp0 (proftype, "video")) {
641 (GstEncodingProfile *) gst_encoding_video_profile_new (formatcaps,
642 preset, restrictioncaps, presence);
643 gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile
644 *) sprof, variableframerate);
645 gst_encoding_video_profile_set_pass ((GstEncodingVideoProfile *) sprof,
647 } else if (!g_strcmp0 (proftype, "audio")) {
649 (GstEncodingProfile *) gst_encoding_audio_profile_new (formatcaps,
650 preset, restrictioncaps, presence);
652 GST_ERROR ("Unknown profile format '%s'", proftype);
655 gst_caps_unref (restrictioncaps);
657 gst_caps_unref (formatcaps);
662 g_free (description);
671 static GstEncodingTarget *
672 parse_keyfile (GKeyFile * in, gchar * targetname, gchar * categoryname,
675 GstEncodingTarget *res = NULL;
676 GstEncodingProfile *prof;
680 res = gst_encoding_target_new (targetname, categoryname, description, NULL);
682 /* Figure out the various profiles */
683 groups = g_key_file_get_groups (in, &nbgroups);
684 for (i = 0; i < nbgroups; i++) {
685 if (!g_ascii_strncasecmp (groups[i], "profile-", 8)) {
686 prof = parse_encoding_profile (in, NULL, groups[i], nbgroups, groups);
688 gst_encoding_target_add_profile (res, prof);
697 g_free (categoryname);
699 g_free (description);
705 load_file_and_read_header (const gchar * path, gchar ** targetname,
706 gchar ** categoryname, gchar ** description, GError ** error)
710 GError *key_error = NULL;
712 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
714 in = g_key_file_new ();
716 GST_DEBUG ("path:%s", path);
719 g_key_file_load_from_file (in, path,
720 G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &key_error);
721 if (!res || key_error != NULL)
726 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", &key_error);
731 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "category", NULL);
733 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "description",
740 GST_WARNING ("Unable to read GstEncodingTarget file %s: %s",
741 path, key_error->message);
742 g_propagate_error (error, key_error);
743 g_key_file_free (in);
749 GST_WARNING ("Wrong header in file %s: %s", path, key_error->message);
750 g_propagate_error (error, key_error);
751 g_key_file_free (in);
757 * gst_encoding_target_load_from_file:
758 * @filepath: The file location to load the #GstEncodingTarget from
759 * @error: If an error occured, this field will be filled in.
761 * Opens the provided file and returns the contained #GstEncodingTarget.
765 * Returns: (transfer full): The #GstEncodingTarget contained in the file, else
770 gst_encoding_target_load_from_file (const gchar * filepath, GError ** error)
773 gchar *targetname, *categoryname, *description;
774 GstEncodingTarget *res = NULL;
776 in = load_file_and_read_header (filepath, &targetname, &categoryname,
777 &description, error);
781 res = parse_keyfile (in, targetname, categoryname, description);
783 g_key_file_free (in);
790 * returned list contents must be freed
793 get_matching_filenames (gchar * path, gchar * filename)
797 const gchar *subdirname;
799 topdir = g_dir_open (path, 0, NULL);
800 if (G_UNLIKELY (topdir == NULL))
803 while ((subdirname = g_dir_read_name (topdir))) {
804 gchar *ltmp = g_build_filename (path, subdirname, NULL);
806 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
807 gchar *tmp = g_build_filename (path, subdirname, filename, NULL);
808 /* Test to see if we have a file named like that in that directory */
809 if (g_file_test (tmp, G_FILE_TEST_EXISTS))
810 res = g_list_append (res, tmp);
817 g_dir_close (topdir);
822 static GstEncodingTarget *
823 gst_encoding_target_subload (gchar * path, const gchar * category,
824 gchar * lfilename, GError ** error)
826 GstEncodingTarget *target = NULL;
831 filename = g_build_filename (path, category, lfilename, NULL);
832 target = gst_encoding_target_load_from_file (filename, error);
835 GList *tmp, *tries = get_matching_filenames (path, lfilename);
837 /* Try to find a file named %s.gstprofile in any subdirectories */
838 for (tmp = tries; tmp; tmp = tmp->next) {
839 target = gst_encoding_target_load_from_file ((gchar *) tmp->data, NULL);
843 g_list_foreach (tries, (GFunc) g_free, NULL);
852 * gst_encoding_target_load:
853 * @name: the name of the #GstEncodingTarget to load.
854 * @category: (allow-none): the name of the target category, like
855 * #GST_ENCODING_CATEGORY_DEVICE. Can be %NULL
856 * @error: If an error occured, this field will be filled in.
858 * Searches for the #GstEncodingTarget with the given name, loads it
861 * 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,
872 gchar *lfilename, *tldir;
873 GstEncodingTarget *target = NULL;
875 g_return_val_if_fail (name != NULL, NULL);
877 if (!validate_name (name))
880 if (category && !validate_name (category))
881 goto invalid_category;
883 lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, name);
885 /* Try from local profiles */
887 g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
888 GST_ENCODING_TARGET_DIRECTORY, NULL);
889 target = gst_encoding_target_subload (tldir, category, lfilename, error);
892 if (target == NULL) {
893 /* Try from system-wide profiles */
895 g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
896 GST_ENCODING_TARGET_DIRECTORY, NULL);
897 target = gst_encoding_target_subload (tldir, category, lfilename, error);
907 GST_ERROR ("Invalid name for encoding target : '%s'", name);
912 GST_ERROR ("Invalid name for encoding category : '%s'", category);
918 * gst_encoding_target_save_to_file:
919 * @target: a #GstEncodingTarget
920 * @filepath: the location to store the @target at.
921 * @error: If an error occured, this field will be filled in.
923 * Saves the @target to the provided file location.
927 * Returns: %TRUE if the target was correctly saved, else %FALSE.
931 gst_encoding_target_save_to_file (GstEncodingTarget * target,
932 const gchar * filepath, GError ** error)
938 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
939 g_return_val_if_fail (filepath != NULL, FALSE);
941 /* FIXME : Check filepath is valid and writable
942 * FIXME : Strip out profiles already present in system target */
944 /* Get unique name... */
946 /* Create output GKeyFile */
947 out = g_key_file_new ();
949 if (!serialize_target (out, target))
950 goto serialize_failure;
952 if (!(data = g_key_file_to_data (out, &data_size, error)))
955 if (!g_file_set_contents (filepath, data, data_size, error))
958 g_key_file_free (out);
965 GST_ERROR ("Failure serializing target");
966 g_key_file_free (out);
972 GST_ERROR ("Failure converting keyfile: %s", (*error)->message);
973 g_key_file_free (out);
980 GST_ERROR ("Unable to write file %s: %s", filepath, (*error)->message);
981 g_key_file_free (out);
988 * gst_encoding_target_save:
989 * @target: a #GstEncodingTarget
990 * @error: If an error occured, this field will be filled in.
992 * Saves the @target to a default user-local directory.
996 * Returns: %TRUE if the target was correctly saved, else %FALSE.
1000 gst_encoding_target_save (GstEncodingTarget * target, GError ** error)
1006 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
1007 g_return_val_if_fail (target->category != NULL, FALSE);
1009 lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, target->name);
1011 g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
1012 GST_ENCODING_TARGET_DIRECTORY, target->category, lfilename, NULL);
1015 res = gst_encoding_target_save_to_file (target, filename, error);
1022 get_categories (gchar * path)
1026 const gchar *subdirname;
1028 topdir = g_dir_open (path, 0, NULL);
1029 if (G_UNLIKELY (topdir == NULL))
1032 while ((subdirname = g_dir_read_name (topdir))) {
1033 gchar *ltmp = g_build_filename (path, subdirname, NULL);
1035 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
1036 res = g_list_append (res, (gpointer) g_strdup (subdirname));
1041 g_dir_close (topdir);
1047 * gst_encoding_list_available_categories:
1049 * Lists all #GstEncodingTarget categories present on disk.
1051 * Returns: (transfer full) (element-type gchar*): A list
1052 * of #GstEncodingTarget categories.
1057 gst_encoding_list_available_categories (void)
1063 /* First try user-local categories */
1064 topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
1065 GST_ENCODING_TARGET_DIRECTORY, NULL);
1066 res = get_categories (topdir);
1069 /* Extend with system-wide categories */
1070 topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
1071 GST_ENCODING_TARGET_DIRECTORY, NULL);
1072 tmp1 = get_categories (topdir);
1075 for (tmp2 = tmp1; tmp2; tmp2 = tmp2->next) {
1076 gchar *name = (gchar *) tmp2->data;
1077 if (!g_list_find_custom (res, name, (GCompareFunc) g_strcmp0))
1078 res = g_list_append (res, (gpointer) name);
1087 static inline GList *
1088 sub_get_all_targets (gchar * subdir)
1091 const gchar *filename;
1093 GstEncodingTarget *target;
1095 dir = g_dir_open (subdir, 0, NULL);
1096 if (G_UNLIKELY (dir == NULL))
1099 while ((filename = g_dir_read_name (dir))) {
1102 /* Only try files ending with .gstprofile */
1103 if (!g_str_has_suffix (filename, GST_ENCODING_TARGET_SUFFIX))
1106 fullname = g_build_filename (subdir, filename, NULL);
1107 target = gst_encoding_target_load_from_file (fullname, NULL);
1109 res = g_list_append (res, target);
1111 GST_WARNING ("Failed to get a target from %s", fullname);
1119 static inline GList *
1120 get_all_targets (gchar * topdir, const gchar * categoryname)
1125 gchar *subdir = g_build_filename (topdir, categoryname, NULL);
1126 /* Try to open the directory */
1127 res = sub_get_all_targets (subdir);
1130 const gchar *subdirname;
1131 GDir *dir = g_dir_open (topdir, 0, NULL);
1133 if (G_UNLIKELY (dir == NULL))
1136 while ((subdirname = g_dir_read_name (dir))) {
1137 gchar *ltmp = g_build_filename (topdir, subdirname, NULL);
1139 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
1140 res = g_list_concat (res, sub_get_all_targets (ltmp));
1151 compare_targets (const GstEncodingTarget * ta, const GstEncodingTarget * tb)
1153 if (!g_strcmp0 (ta->name, tb->name)
1154 && !g_strcmp0 (ta->category, tb->category))
1161 * gst_encoding_list_all_targets:
1162 * @categoryname: (allow-none): The category, for ex: #GST_ENCODING_CATEGORY_DEVICE.
1165 * List all available #GstEncodingTarget for the specified category, or all categories
1166 * if @categoryname is %NULL.
1168 * Returns: (transfer full) (element-type GstEncodingTarget): The list of #GstEncodingTarget
1173 gst_encoding_list_all_targets (const gchar * categoryname)
1179 /* Get user-locals */
1180 topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
1181 GST_ENCODING_TARGET_DIRECTORY, NULL);
1182 res = get_all_targets (topdir, categoryname);
1185 /* Get system-wide */
1186 topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
1187 GST_ENCODING_TARGET_DIRECTORY, NULL);
1188 tmp1 = get_all_targets (topdir, categoryname);
1191 /* Merge system-wide targets */
1192 /* FIXME : We should merge the system-wide profiles into the user-locals
1193 * instead of stopping at identical target names */
1194 for (tmp2 = tmp1; tmp2; tmp2 = tmp2->next) {
1195 GstEncodingTarget *target = (GstEncodingTarget *) tmp2->data;
1196 if (g_list_find_custom (res, target, (GCompareFunc) compare_targets))
1197 gst_encoding_target_unref (target);
1199 res = g_list_append (res, target);