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.
26 #include "encoding-target.h"
33 * [_gstencodingtarget_]
35 * category : <category>
36 * description : <description> #translatable
38 * [profile-<profile1name>]
40 * description : <description> #optional
44 * [streamprofile-<id>]
45 * parent : <encodingprofile.name>[,<encodingprofile.name>..]
46 * type : <type> # "audio", "video", "text"
49 * restriction : <restriction>
50 * presence : <presence>
52 * variableframerate : <variableframerate>
56 * Location of profile files
58 * $GST_DATADIR/gstreamer-GST_MAJORMINOR/encoding-profile
59 * $HOME/gstreamer-GST_MAJORMINOR/encoding-profile
62 * $(target.category)/$(target.name).gstprof
64 * Naming restrictions:
65 * lowercase ASCII letter for the first character
66 * Same for all other characters + numerics + hyphens
70 #define GST_ENCODING_TARGET_HEADER "_gstencodingtarget_"
71 #define GST_ENCODING_TARGET_DIRECTORY "encoding-profiles"
72 #define GST_ENCODING_TARGET_SUFFIX ".gep"
74 struct _GstEncodingTarget
87 G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, GST_TYPE_MINI_OBJECT);
90 gst_encoding_target_init (GstEncodingTarget * target)
92 /* Nothing to initialize */
96 gst_encoding_target_finalize (GstEncodingTarget * target)
98 GST_DEBUG ("Finalizing");
101 g_free (target->name);
102 if (target->category)
103 g_free (target->category);
104 if (target->description)
105 g_free (target->description);
107 g_list_foreach (target->profiles, (GFunc) gst_mini_object_unref, NULL);
108 g_list_free (target->profiles);
112 gst_encoding_target_class_init (GstMiniObjectClass * klass)
115 (GstMiniObjectFinalizeFunction) gst_encoding_target_finalize;
119 * gst_encoding_target_get_name:
120 * @target: a #GstEncodingTarget
124 * Returns: (transfer none): The name of the @target.
127 gst_encoding_target_get_name (GstEncodingTarget * target)
133 * gst_encoding_target_get_category:
134 * @target: a #GstEncodingTarget
138 * Returns: (transfer none): The category of the @target. For example:
139 * #GST_ENCODING_CATEGORY_DEVICE.
142 gst_encoding_target_get_category (GstEncodingTarget * target)
144 return target->category;
148 * gst_encoding_target_get_description:
149 * @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
167 * Returns: (transfer none) (element-type Gst.EncodingProfile): A list of
168 * #GstEncodingProfile(s) this @target handles.
171 gst_encoding_target_get_profiles (GstEncodingTarget * target)
173 return target->profiles;
177 * gst_encoding_target_get_profile:
178 * @target: a #GstEncodingTarget
179 * @name: the name of the profile to retrieve
183 * Returns: (transfer full): The matching #GstEncodingProfile, or %NULL.
186 gst_encoding_target_get_profile (GstEncodingTarget * target, const gchar * name)
190 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), NULL);
191 g_return_val_if_fail (name != NULL, NULL);
193 for (tmp = target->profiles; tmp; tmp = tmp->next) {
194 GstEncodingProfile *tprof = (GstEncodingProfile *) tmp->data;
196 if (!g_strcmp0 (gst_encoding_profile_get_name (tprof), name)) {
197 gst_encoding_profile_ref (tprof);
205 static inline gboolean
206 validate_name (const gchar * name)
214 /* First character can only be a lower case ASCII character */
215 if (!g_ascii_isalpha (name[0]) || !g_ascii_islower (name[0]))
218 /* All following characters can only by:
219 * either a lower case ASCII character
222 for (i = 1; i < len; i++) {
223 /* if uppercase ASCII letter, return */
224 if (g_ascii_isupper (name[i]))
226 /* if a digit, continue */
227 if (g_ascii_isdigit (name[i]))
229 /* if an hyphen, continue */
232 /* remaining should only be ascii letters */
233 if (!g_ascii_isalpha (name[i]))
241 * gst_encoding_target_new:
242 * @name: The name of the target.
243 * @category: (transfer none): The name of the category to which this @target
244 * belongs. For example: #GST_ENCODING_CATEGORY_DEVICE.
245 * @description: (transfer none): A description of #GstEncodingTarget in the
247 * @profiles: (transfer none) (element-type Gst.EncodingProfile): A #GList of
248 * #GstEncodingProfile.
250 * Creates a new #GstEncodingTarget.
252 * The name and category can only consist of lowercase ASCII letters for the
253 * first character, followed by either lowercase ASCII letters, digits or
256 * The @category *should* be one of the existing well-defined categories, like
257 * #GST_ENCODING_CATEGORY_DEVICE, but it *can* be a application or user specific
258 * category if needed.
262 * Returns: (transfer full): The newly created #GstEncodingTarget or %NULL if
263 * there was an error.
267 gst_encoding_target_new (const gchar * name, const gchar * category,
268 const gchar * description, const GList * profiles)
270 GstEncodingTarget *res;
272 g_return_val_if_fail (name != NULL, NULL);
273 g_return_val_if_fail (category != NULL, NULL);
274 g_return_val_if_fail (description != NULL, NULL);
277 if (!validate_name (name))
279 if (!validate_name (category))
280 goto invalid_category;
282 res = (GstEncodingTarget *) gst_mini_object_new (GST_TYPE_ENCODING_TARGET);
283 res->name = g_strdup (name);
284 res->category = g_strdup (category);
285 res->description = g_strdup (description);
288 GstEncodingProfile *prof = (GstEncodingProfile *) profiles->data;
291 g_list_append (res->profiles, gst_encoding_profile_ref (prof));
292 profiles = profiles->next;
299 GST_ERROR ("Invalid name for encoding target : '%s'", name);
305 GST_ERROR ("Invalid name for encoding category : '%s'", category);
311 * gst_encoding_target_add_profile:
312 * @target: the #GstEncodingTarget to add a profile to
313 * @profile: (transfer full): the #GstEncodingProfile to add
315 * Adds the given @profile to the @target. Each added profile must have
316 * a unique name within the profile.
318 * The @target will steal a reference to the @profile. If you wish to use
319 * the profile after calling this method, you should increase its reference
324 * Returns: %TRUE if the profile was added, else %FALSE.
328 gst_encoding_target_add_profile (GstEncodingTarget * target,
329 GstEncodingProfile * profile)
333 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
334 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
336 /* Make sure profile isn't already controlled by this target */
337 for (tmp = target->profiles; tmp; tmp = tmp->next) {
338 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
340 if (!g_strcmp0 (gst_encoding_profile_get_name (profile),
341 gst_encoding_profile_get_name (prof))) {
342 GST_WARNING ("Profile already present in target");
347 target->profiles = g_list_append (target->profiles, profile);
353 serialize_stream_profiles (GKeyFile * out, GstEncodingProfile * sprof,
354 const gchar * profilename, guint id)
356 gchar *sprofgroupname;
358 const GstCaps *format, *restriction;
359 const gchar *preset, *name, *description;
361 sprofgroupname = g_strdup_printf ("streamprofile-%s-%d", profilename, id);
363 /* Write the parent profile */
364 g_key_file_set_value (out, sprofgroupname, "parent", profilename);
366 g_key_file_set_value (out, sprofgroupname, "type",
367 gst_encoding_profile_get_type_nick (sprof));
369 format = gst_encoding_profile_get_format (sprof);
371 tmpc = gst_caps_to_string (format);
372 g_key_file_set_value (out, sprofgroupname, "format", tmpc);
376 name = gst_encoding_profile_get_name (sprof);
378 g_key_file_set_string (out, sprofgroupname, "name", name);
380 description = gst_encoding_profile_get_description (sprof);
382 g_key_file_set_string (out, sprofgroupname, "description", description);
384 preset = gst_encoding_profile_get_preset (sprof);
386 g_key_file_set_string (out, sprofgroupname, "preset", preset);
388 restriction = gst_encoding_profile_get_restriction (sprof);
390 tmpc = gst_caps_to_string (restriction);
391 g_key_file_set_value (out, sprofgroupname, "restriction", tmpc);
394 g_key_file_set_integer (out, sprofgroupname, "presence",
395 gst_encoding_profile_get_presence (sprof));
397 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
398 GstEncodingVideoProfile *vp = (GstEncodingVideoProfile *) sprof;
400 g_key_file_set_integer (out, sprofgroupname, "pass",
401 gst_encoding_video_profile_get_pass (vp));
402 g_key_file_set_boolean (out, sprofgroupname, "variableframerate",
403 gst_encoding_video_profile_get_variableframerate (vp));
406 g_free (sprofgroupname);
410 /* Serialize the top-level profiles
411 * Note: They don't have to be containerprofiles */
413 serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof)
415 gchar *profgroupname;
418 const gchar *profname, *profdesc, *profpreset, *proftype;
419 const GstCaps *profformat, *profrestriction;
421 profname = gst_encoding_profile_get_name (prof);
422 profdesc = gst_encoding_profile_get_description (prof);
423 profformat = gst_encoding_profile_get_format (prof);
424 profpreset = gst_encoding_profile_get_preset (prof);
425 proftype = gst_encoding_profile_get_type_nick (prof);
426 profrestriction = gst_encoding_profile_get_restriction (prof);
428 profgroupname = g_strdup_printf ("profile-%s", profname);
430 g_key_file_set_string (out, profgroupname, "name", profname);
432 g_key_file_set_value (out, profgroupname, "type",
433 gst_encoding_profile_get_type_nick (prof));
436 g_key_file_set_locale_string (out, profgroupname, "description",
437 setlocale (LC_ALL, NULL), profdesc);
439 gchar *tmpc = gst_caps_to_string (profformat);
440 g_key_file_set_string (out, profgroupname, "format", tmpc);
444 g_key_file_set_string (out, profgroupname, "preset", profpreset);
446 /* stream profiles */
447 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
449 gst_encoding_container_profile_get_profiles
450 (GST_ENCODING_CONTAINER_PROFILE (prof)), i = 0; tmp;
451 tmp = tmp->next, i++) {
452 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
454 if (!serialize_stream_profiles (out, sprof, profname, i))
458 g_free (profgroupname);
463 serialize_target (GKeyFile * out, GstEncodingTarget * target)
467 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "name", target->name);
468 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "category",
470 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "description",
471 target->description);
473 for (tmp = target->profiles; tmp; tmp = tmp->next) {
474 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
475 if (!serialize_encoding_profile (out, prof))
483 * parse_encoding_profile:
485 * @parentprofilename: the parent profile name (including 'profile-' or 'streamprofile-' header)
486 * @profilename: the profile name group to parse
487 * @nbgroups: the number of top-level groups
488 * @groups: the top-level groups
490 static GstEncodingProfile *
491 parse_encoding_profile (GKeyFile * in, gchar * parentprofilename,
492 gchar * profilename, gsize nbgroups, gchar ** groups)
494 GstEncodingProfile *sprof = NULL;
496 gchar *proftype, *format, *preset, *restriction, *pname, *description;
497 GstCaps *formatcaps = NULL;
498 GstCaps *restrictioncaps = NULL;
499 gboolean variableframerate;
501 gsize i, nbencprofiles;
503 GST_DEBUG ("parentprofilename : %s , profilename : %s",
504 parentprofilename, profilename);
506 if (parentprofilename) {
507 gboolean found = FALSE;
510 g_key_file_get_string_list (in, profilename, "parent",
511 &nbencprofiles, NULL);
512 if (!parent || !nbencprofiles) {
516 /* Check if this streamprofile is used in <profilename> */
517 for (i = 0; i < nbencprofiles; i++) {
518 if (!g_strcmp0 (parent[i], parentprofilename)) {
526 GST_DEBUG ("Stream profile '%s' isn't used in profile '%s'",
527 profilename, parentprofilename);
532 pname = g_key_file_get_value (in, profilename, "name", NULL);
534 /* First try to get localized description */
536 g_key_file_get_locale_string (in, profilename, "description",
537 setlocale (LC_ALL, NULL), NULL);
538 if (description == NULL)
539 description = g_key_file_get_value (in, profilename, "description", NULL);
541 /* Parse the remaining fields */
542 proftype = g_key_file_get_value (in, profilename, "type", NULL);
544 GST_WARNING ("Missing 'type' field for streamprofile %s", profilename);
548 format = g_key_file_get_value (in, profilename, "format", NULL);
550 formatcaps = gst_caps_from_string (format);
554 preset = g_key_file_get_value (in, profilename, "preset", NULL);
556 restriction = g_key_file_get_value (in, profilename, "restriction", NULL);
558 restrictioncaps = gst_caps_from_string (restriction);
559 g_free (restriction);
562 presence = g_key_file_get_integer (in, profilename, "presence", NULL);
563 pass = g_key_file_get_integer (in, profilename, "pass", NULL);
565 g_key_file_get_boolean (in, profilename, "variableframerate", NULL);
567 /* Build the streamprofile ! */
568 if (!g_strcmp0 (proftype, "container")) {
569 GstEncodingProfile *pprof;
572 (GstEncodingProfile *) gst_encoding_container_profile_new (pname,
573 description, formatcaps, preset);
574 /* Now look for the stream profiles */
575 for (i = 0; i < nbgroups; i++) {
576 if (!g_ascii_strncasecmp (groups[i], "streamprofile-", 13)) {
577 pprof = parse_encoding_profile (in, pname, groups[i], nbgroups, groups);
579 gst_encoding_container_profile_add_profile (
580 (GstEncodingContainerProfile *) sprof, pprof);
584 } else if (!g_strcmp0 (proftype, "video")) {
586 (GstEncodingProfile *) gst_encoding_video_profile_new (formatcaps,
587 preset, restrictioncaps, presence);
588 gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile
589 *) sprof, variableframerate);
590 gst_encoding_video_profile_set_pass ((GstEncodingVideoProfile *) sprof,
592 } else if (!g_strcmp0 (proftype, "audio")) {
594 (GstEncodingProfile *) gst_encoding_audio_profile_new (formatcaps,
595 preset, restrictioncaps, presence);
597 GST_ERROR ("Unknown profile format '%s'", proftype);
600 gst_caps_unref (restrictioncaps);
602 gst_caps_unref (formatcaps);
607 g_free (description);
616 static GstEncodingTarget *
617 parse_keyfile (GKeyFile * in, gchar * targetname, gchar * categoryname,
620 GstEncodingTarget *res = NULL;
621 GstEncodingProfile *prof;
625 res = gst_encoding_target_new (targetname, categoryname, description, NULL);
627 /* Figure out the various profiles */
628 groups = g_key_file_get_groups (in, &nbgroups);
629 for (i = 0; i < nbgroups; i++) {
630 if (!g_ascii_strncasecmp (groups[i], "profile-", 8)) {
631 prof = parse_encoding_profile (in, NULL, groups[i], nbgroups, groups);
633 gst_encoding_target_add_profile (res, prof);
642 g_free (categoryname);
644 g_free (description);
650 load_file_and_read_header (const gchar * path, gchar ** targetname,
651 gchar ** categoryname, gchar ** description, GError ** error)
656 in = g_key_file_new ();
658 GST_DEBUG ("path:%s", path);
661 g_key_file_load_from_file (in, path,
662 G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, error);
663 if (!res || error != NULL)
667 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", error);
672 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "category", NULL);
674 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "description",
681 GST_WARNING ("Unable to read GstEncodingTarget file %s: %s",
682 path, (*error)->message);
683 g_key_file_free (in);
689 GST_WARNING ("Wrong header in file %s: %s", path, (*error)->message);
690 g_key_file_free (in);
696 * gst_encoding_target_load_from:
697 * @path: The file to load the #GstEncodingTarget from
698 * @error: If an error occured, this field will be filled in.
700 * Opens the provided file and returns the contained #GstEncodingTarget.
704 * Returns: (transfer full): The #GstEncodingTarget contained in the file, else
709 gst_encoding_target_load_from (const gchar * path, GError ** error)
712 gchar *targetname, *categoryname, *description;
713 GstEncodingTarget *res = NULL;
715 in = load_file_and_read_header (path, &targetname, &categoryname,
716 &description, error);
720 res = parse_keyfile (in, targetname, categoryname, description);
722 g_key_file_free (in);
729 * returned list contents must be freed
732 get_matching_filenames (gchar * path, gchar * filename)
736 const gchar *subdirname;
738 topdir = g_dir_open (path, 0, NULL);
739 if (G_UNLIKELY (topdir == NULL))
742 while ((subdirname = g_dir_read_name (topdir))) {
743 gchar *ltmp = g_build_filename (path, subdirname, NULL);
745 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
746 gchar *tmp = g_build_filename (path, subdirname, filename, NULL);
747 /* Test to see if we have a file named like that in that directory */
748 if (g_file_test (tmp, G_FILE_TEST_EXISTS))
749 res = g_list_append (res, tmp);
756 g_dir_close (topdir);
761 static GstEncodingTarget *
762 gst_encoding_target_subload (gchar * path, const gchar * category,
763 gchar * lfilename, GError ** error)
765 GstEncodingTarget *target = NULL;
770 filename = g_build_filename (path, category, lfilename, NULL);
771 target = gst_encoding_target_load_from (filename, error);
774 GList *tmp, *tries = get_matching_filenames (path, lfilename);
776 /* Try to find a file named %s.gstprofile in any subdirectories */
777 for (tmp = tries; tmp; tmp = tmp->next) {
778 target = gst_encoding_target_load_from ((gchar *) tmp->data, NULL);
782 g_list_foreach (tries, (GFunc) g_free, NULL);
791 * gst_encoding_target_load:
792 * @name: the name of the #GstEncodingTarget to load.
793 * @category: (allow-none): the name of the target category, like
794 * #GST_ENCODING_CATEGORY_DEVICE. Can be %NULL
795 * @error: If an error occured, this field will be filled in.
797 * Searches for the #GstEncodingTarget with the given name, loads it
800 * If the category name is specified only targets from that category will be
805 * Returns: (transfer full): The #GstEncodingTarget if available, else %NULL.
808 gst_encoding_target_load (const gchar * name, const gchar * category,
811 gchar *lfilename, *tldir;
812 GstEncodingTarget *target = NULL;
814 g_return_val_if_fail (name != NULL, NULL);
816 if (!validate_name (name))
819 if (category && !validate_name (category))
820 goto invalid_category;
822 lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, name);
824 /* Try from local profiles */
826 g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
827 GST_ENCODING_TARGET_DIRECTORY, NULL);
828 target = gst_encoding_target_subload (tldir, category, lfilename, error);
831 if (target == NULL) {
832 /* Try from system-wide profiles */
834 g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
835 GST_ENCODING_TARGET_DIRECTORY, NULL);
836 target = gst_encoding_target_subload (tldir, category, lfilename, error);
846 GST_ERROR ("Invalid name for encoding target : '%s'", name);
851 GST_ERROR ("Invalid name for encoding category : '%s'", category);
857 * gst_encoding_target_save_to:
858 * @target: a #GstEncodingTarget
859 * @path: the location to store the @target at.
860 * @error: If an error occured, this field will be filled in.
862 * Saves the @target to the provided location.
866 * Returns: %TRUE if the target was correctly saved, else %FALSE.
870 gst_encoding_target_save_to (GstEncodingTarget * target, const gchar * path,
877 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
878 g_return_val_if_fail (path != NULL, FALSE);
880 /* FIXME : Check path is valid and writable
881 * FIXME : Strip out profiles already present in system target */
883 /* Get unique name... */
885 /* Create output GKeyFile */
886 out = g_key_file_new ();
888 if (!serialize_target (out, target))
889 goto serialize_failure;
891 if (!(data = g_key_file_to_data (out, &data_size, error)))
894 if (!g_file_set_contents (path, data, data_size, error))
897 g_key_file_free (out);
904 GST_ERROR ("Failure serializing target");
905 g_key_file_free (out);
911 GST_ERROR ("Failure converting keyfile: %s", (*error)->message);
912 g_key_file_free (out);
919 GST_ERROR ("Unable to write file %s: %s", path, (*error)->message);
920 g_key_file_free (out);
927 * gst_encoding_target_save:
928 * @target: a #GstEncodingTarget
929 * @error: If an error occured, this field will be filled in.
931 * Saves the @target to a default user-local directory.
935 * Returns: %TRUE if the target was correctly saved, else %FALSE.
939 gst_encoding_target_save (GstEncodingTarget * target, GError ** error)
945 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
946 g_return_val_if_fail (target->category != NULL, FALSE);
948 lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, target->name);
950 g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
951 GST_ENCODING_TARGET_DIRECTORY, target->category, lfilename, NULL);
954 res = gst_encoding_target_save_to (target, filename, error);
961 get_categories (gchar * path)
965 const gchar *subdirname;
967 topdir = g_dir_open (path, 0, NULL);
968 if (G_UNLIKELY (topdir == NULL))
971 while ((subdirname = g_dir_read_name (topdir))) {
972 gchar *ltmp = g_build_filename (path, subdirname, NULL);
974 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
975 res = g_list_append (res, (gpointer) g_strdup (subdirname));
980 g_dir_close (topdir);
986 * gst_encoding_list_available_categories:
988 * Lists all #GstEncodingTarget categories present on disk.
990 * Returns: (transfer full) (element-type gchar*): A list
991 * of #GstEncodingTarget categories.
994 gst_encoding_list_available_categories (void)
1000 /* First try user-local categories */
1001 topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
1002 GST_ENCODING_TARGET_DIRECTORY, NULL);
1003 res = get_categories (topdir);
1006 /* Extend with system-wide categories */
1007 topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
1008 GST_ENCODING_TARGET_DIRECTORY, NULL);
1009 tmp1 = get_categories (topdir);
1012 for (tmp2 = tmp1; tmp2; tmp2 = tmp2->next) {
1013 gchar *name = (gchar *) tmp2->data;
1014 if (!g_list_find_custom (res, name, (GCompareFunc) g_strcmp0))
1015 res = g_list_append (res, (gpointer) name);
1024 static inline GList *
1025 sub_get_all_targets (gchar * subdir)
1028 const gchar *filename;
1030 GstEncodingTarget *target;
1032 dir = g_dir_open (subdir, 0, NULL);
1033 if (G_UNLIKELY (dir == NULL))
1036 while ((filename = g_dir_read_name (dir))) {
1039 /* Only try files ending with .gstprofile */
1040 if (!g_str_has_suffix (filename, GST_ENCODING_TARGET_SUFFIX))
1043 fullname = g_build_filename (subdir, filename, NULL);
1044 target = gst_encoding_target_load_from (fullname, NULL);
1046 res = g_list_append (res, target);
1048 GST_WARNING ("Failed to get a target from %s", fullname);
1056 static inline GList *
1057 get_all_targets (gchar * topdir, const gchar * categoryname)
1062 gchar *subdir = g_build_filename (topdir, categoryname, NULL);
1063 /* Try to open the directory */
1064 res = sub_get_all_targets (subdir);
1067 const gchar *subdirname;
1068 GDir *dir = g_dir_open (topdir, 0, NULL);
1070 if (G_UNLIKELY (dir == NULL))
1073 while ((subdirname = g_dir_read_name (dir))) {
1074 gchar *ltmp = g_build_filename (topdir, subdirname, NULL);
1076 if (g_file_test (ltmp, G_FILE_TEST_IS_DIR)) {
1077 res = g_list_concat (res, sub_get_all_targets (ltmp));
1088 compare_targets (const GstEncodingTarget * ta, const GstEncodingTarget * tb)
1090 if (!g_strcmp0 (ta->name, tb->name)
1091 && !g_strcmp0 (ta->category, tb->category))
1098 * gst_encoding_list_all_targets:
1099 * @categoryname: (allow-none): The category, for ex: #GST_ENCODING_CATEGORY_DEVICE.
1102 * List all available #GstEncodingTarget for the specified category, or all categories
1103 * if @categoryname is NULL.
1105 * Returns: (transfer full) (element-type GstEncodingTarget): The list of #GstEncodingTarget
1108 gst_encoding_list_all_targets (const gchar * categoryname)
1114 /* Get user-locals */
1115 topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
1116 GST_ENCODING_TARGET_DIRECTORY, NULL);
1117 res = get_all_targets (topdir, categoryname);
1120 /* Get system-wide */
1121 topdir = g_build_filename (GST_DATADIR, "gstreamer-" GST_MAJORMINOR,
1122 GST_ENCODING_TARGET_DIRECTORY, NULL);
1123 tmp1 = get_all_targets (topdir, categoryname);
1126 /* Merge system-wide targets */
1127 /* FIXME : We should merge the system-wide profiles into the user-locals
1128 * instead of stopping at identical target names */
1129 for (tmp2 = tmp1; tmp2; tmp2 = tmp2->next) {
1130 GstEncodingTarget *target = (GstEncodingTarget *) tmp2->data;
1131 if (g_list_find_custom (res, target, (GCompareFunc) compare_targets))
1132 gst_encoding_target_unref (target);
1134 res = g_list_append (res, target);