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.
22 #include "encoding-target.h"
29 * [_gstencodingtarget_]
31 * category : <category>
32 * description : <description> #translatable
34 * [profile-<profile1name>]
36 * description : <description> #optional
40 * [streamprofile-<id>]
41 * parent : <encodingprofile.name>[,<encodingprofile.name>..]
42 * type : <type> # "audio", "video", "text"
45 * restriction : <restriction>
46 * presence : <presence>
48 * variableframerate : <variableframerate>
51 #define GST_ENCODING_TARGET_HEADER "_gstencodingtarget_"
53 struct _GstEncodingTarget
66 G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, GST_TYPE_MINI_OBJECT);
69 gst_encoding_target_init (GstEncodingTarget * target)
71 /* Nothing to initialize */
75 gst_encoding_target_finalize (GstEncodingTarget * target)
77 GST_DEBUG ("Finalizing");
80 g_free (target->name);
82 g_free (target->category);
83 if (target->description)
84 g_free (target->description);
86 g_list_foreach (target->profiles, (GFunc) gst_mini_object_unref, NULL);
87 g_list_free (target->profiles);
91 gst_encoding_target_class_init (GstMiniObjectClass * klass)
94 (GstMiniObjectFinalizeFunction) gst_encoding_target_finalize;
98 * gst_encoding_target_get_name:
99 * @target: a #GstEncodingTarget
103 * Returns: The name of the @target.
106 gst_encoding_target_get_name (GstEncodingTarget * target)
112 * gst_encoding_target_get_category:
113 * @target: a #GstEncodingTarget
117 * Returns: The category of the @target.
120 gst_encoding_target_get_category (GstEncodingTarget * target)
122 return target->category;
126 * gst_encoding_target_get_description:
127 * @target: a #GstEncodingTarget
131 * Returns: The description of the @target.
134 gst_encoding_target_get_description (GstEncodingTarget * target)
136 return target->description;
140 * gst_encoding_target_get_profiles:
141 * @target: a #GstEncodingTarget
145 * Returns: A list of #GstEncodingProfile(s) this @target handles.
148 gst_encoding_target_get_profiles (GstEncodingTarget * target)
150 return target->profiles;
155 * gst_encoding_target_new:
156 * @name: The name of the target.
157 * @category: The name of the category to which this @target belongs.
158 * @description: A description of #GstEncodingTarget in the current locale.
159 * @profiles: A #GList of #GstEncodingProfile.
161 * Creates a new #GstEncodingTarget.
165 * Returns: The newly created #GstEncodingTarget or %NULL if there was an
170 gst_encoding_target_new (const gchar * name, const gchar * category,
171 const gchar * description, const GList * profiles)
173 GstEncodingTarget *res;
175 g_return_val_if_fail (name != NULL, NULL);
176 g_return_val_if_fail (category != NULL, NULL);
177 g_return_val_if_fail (description != NULL, NULL);
179 res = (GstEncodingTarget *) gst_mini_object_new (GST_TYPE_ENCODING_TARGET);
180 res->name = g_strdup (name);
181 res->category = g_strdup (category);
182 res->description = g_strdup (description);
185 GstEncodingProfile *prof = (GstEncodingProfile *) profiles->data;
188 g_list_append (res->profiles, gst_encoding_profile_ref (prof));
189 profiles = profiles->next;
196 * gst_encoding_target_add_profile:
197 * @target: the #GstEncodingTarget to add a profile to
198 * @profile: the #GstEncodingProfile to add
200 * Adds the given @profile to the @target.
202 * The @target will steal a reference to the @profile. If you wish to use
203 * the profile after calling this method, you should increase its reference
208 * Returns: %TRUE if the profile was added, else %FALSE.
212 gst_encoding_target_add_profile (GstEncodingTarget * target,
213 GstEncodingProfile * profile)
217 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
218 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
220 /* Make sure profile isn't already controlled by this target */
221 for (tmp = target->profiles; tmp; tmp = tmp->next) {
222 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
224 if (!g_strcmp0 (gst_encoding_profile_get_name (profile),
225 gst_encoding_profile_get_name (prof))) {
226 GST_WARNING ("Profile already present in target");
231 target->profiles = g_list_append (target->profiles, profile);
237 serialize_stream_profiles (GKeyFile * out, GstEncodingProfile * sprof,
238 const gchar * profilename, guint id)
240 gchar *sprofgroupname;
242 const GstCaps *format, *restriction;
243 const gchar *preset, *name, *description;
245 sprofgroupname = g_strdup_printf ("streamprofile-%s-%d", profilename, id);
247 /* Write the parent profile */
248 g_key_file_set_value (out, sprofgroupname, "parent", profilename);
250 g_key_file_set_value (out, sprofgroupname, "type",
251 gst_encoding_profile_get_type_nick (sprof));
253 format = gst_encoding_profile_get_format (sprof);
255 tmpc = gst_caps_to_string (format);
256 g_key_file_set_value (out, sprofgroupname, "format", tmpc);
260 name = gst_encoding_profile_get_name (sprof);
262 g_key_file_set_string (out, sprofgroupname, "name", name);
264 description = gst_encoding_profile_get_description (sprof);
266 g_key_file_set_string (out, sprofgroupname, "description", description);
268 preset = gst_encoding_profile_get_preset (sprof);
270 g_key_file_set_string (out, sprofgroupname, "preset", preset);
272 restriction = gst_encoding_profile_get_restriction (sprof);
274 tmpc = gst_caps_to_string (restriction);
275 g_key_file_set_value (out, sprofgroupname, "restriction", tmpc);
278 g_key_file_set_integer (out, sprofgroupname, "presence",
279 gst_encoding_profile_get_presence (sprof));
281 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
282 GstEncodingVideoProfile *vp = (GstEncodingVideoProfile *) sprof;
284 g_key_file_set_integer (out, sprofgroupname, "pass",
285 gst_encoding_video_profile_get_pass (vp));
286 g_key_file_set_boolean (out, sprofgroupname, "variableframerate",
287 gst_encoding_video_profile_get_variableframerate (vp));
290 g_free (sprofgroupname);
294 /* Serialize the top-level profiles
295 * Note: They don't have to be containerprofiles */
297 serialize_encoding_profile (GKeyFile * out, GstEncodingProfile * prof)
299 gchar *profgroupname;
302 const gchar *profname, *profdesc, *profpreset, *proftype;
303 const GstCaps *profformat, *profrestriction;
305 profname = gst_encoding_profile_get_name (prof);
306 profdesc = gst_encoding_profile_get_description (prof);
307 profformat = gst_encoding_profile_get_format (prof);
308 profpreset = gst_encoding_profile_get_preset (prof);
309 proftype = gst_encoding_profile_get_type_nick (prof);
310 profrestriction = gst_encoding_profile_get_restriction (prof);
312 profgroupname = g_strdup_printf ("profile-%s", profname);
314 g_key_file_set_string (out, profgroupname, "name", profname);
316 g_key_file_set_value (out, profgroupname, "type",
317 gst_encoding_profile_get_type_nick (prof));
320 g_key_file_set_locale_string (out, profgroupname, "description",
321 setlocale (LC_ALL, NULL), profdesc);
323 gchar *tmpc = gst_caps_to_string (profformat);
324 g_key_file_set_string (out, profgroupname, "format", tmpc);
328 g_key_file_set_string (out, profgroupname, "preset", profpreset);
330 /* stream profiles */
331 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
333 gst_encoding_container_profile_get_profiles
334 (GST_ENCODING_CONTAINER_PROFILE (prof)), i = 0; tmp;
335 tmp = tmp->next, i++) {
336 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
338 if (!serialize_stream_profiles (out, sprof, profname, i))
342 g_free (profgroupname);
347 serialize_target (GKeyFile * out, GstEncodingTarget * target)
351 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "name", target->name);
352 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "category",
354 g_key_file_set_string (out, GST_ENCODING_TARGET_HEADER, "description",
355 target->description);
357 for (tmp = target->profiles; tmp; tmp = tmp->next) {
358 GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
359 if (!serialize_encoding_profile (out, prof))
367 * parse_encoding_profile:
369 * @parentprofilename: the parent profile name (including 'profile-' or 'streamprofile-' header)
370 * @profilename: the profile name group to parse
371 * @nbgroups: the number of top-level groups
372 * @groups: the top-level groups
374 static GstEncodingProfile *
375 parse_encoding_profile (GKeyFile * in, gchar * parentprofilename,
376 gchar * profilename, gsize nbgroups, gchar ** groups)
378 GstEncodingProfile *sprof = NULL;
380 gchar *proftype, *format, *preset, *restriction, *pname, *description;
381 GstCaps *formatcaps = NULL;
382 GstCaps *restrictioncaps = NULL;
383 gboolean variableframerate;
385 gsize i, nbencprofiles;
387 GST_DEBUG ("parentprofilename : %s , profilename : %s",
388 parentprofilename, profilename);
390 if (parentprofilename) {
391 gboolean found = FALSE;
394 g_key_file_get_string_list (in, profilename, "parent",
395 &nbencprofiles, NULL);
396 if (!parent || !nbencprofiles) {
400 /* Check if this streamprofile is used in <profilename> */
401 for (i = 0; i < nbencprofiles; i++) {
402 if (!g_strcmp0 (parent[i], parentprofilename)) {
410 GST_DEBUG ("Stream profile '%s' isn't used in profile '%s'",
411 profilename, parentprofilename);
416 pname = g_key_file_get_value (in, profilename, "name", NULL);
418 /* First try to get localized description */
420 g_key_file_get_locale_string (in, profilename, "description",
421 setlocale (LC_ALL, NULL), NULL);
422 if (description == NULL)
423 description = g_key_file_get_value (in, profilename, "description", NULL);
425 /* Parse the remaining fields */
426 proftype = g_key_file_get_value (in, profilename, "type", NULL);
428 GST_WARNING ("Missing 'type' field for streamprofile %s", profilename);
432 format = g_key_file_get_value (in, profilename, "format", NULL);
434 formatcaps = gst_caps_from_string (format);
438 preset = g_key_file_get_value (in, profilename, "preset", NULL);
440 restriction = g_key_file_get_value (in, profilename, "restriction", NULL);
442 restrictioncaps = gst_caps_from_string (restriction);
443 g_free (restriction);
446 presence = g_key_file_get_integer (in, profilename, "presence", NULL);
447 pass = g_key_file_get_integer (in, profilename, "pass", NULL);
449 g_key_file_get_boolean (in, profilename, "variableframerate", NULL);
451 /* Build the streamprofile ! */
452 if (!g_strcmp0 (proftype, "container")) {
453 GstEncodingProfile *pprof;
456 (GstEncodingProfile *) gst_encoding_container_profile_new (pname,
457 description, formatcaps, preset);
458 /* Now look for the stream profiles */
459 for (i = 0; i < nbgroups; i++) {
460 if (!g_ascii_strncasecmp (groups[i], "streamprofile-", 13)) {
461 pprof = parse_encoding_profile (in, pname, groups[i], nbgroups, groups);
463 gst_encoding_container_profile_add_profile (
464 (GstEncodingContainerProfile *) sprof, pprof);
468 } else if (!g_strcmp0 (proftype, "video")) {
470 (GstEncodingProfile *) gst_encoding_video_profile_new (formatcaps,
471 preset, restrictioncaps, presence);
472 gst_encoding_video_profile_set_variableframerate ((GstEncodingVideoProfile
473 *) sprof, variableframerate);
474 gst_encoding_video_profile_set_pass ((GstEncodingVideoProfile *) sprof,
476 } else if (!g_strcmp0 (proftype, "audio")) {
478 (GstEncodingProfile *) gst_encoding_audio_profile_new (formatcaps,
479 preset, restrictioncaps, presence);
481 GST_ERROR ("Unknown profile format '%s'", proftype);
484 gst_caps_unref (restrictioncaps);
486 gst_caps_unref (formatcaps);
491 g_free (description);
500 static GstEncodingTarget *
501 parse_keyfile (GKeyFile * in, gchar * targetname, gchar * categoryname,
504 GstEncodingTarget *res = NULL;
505 GstEncodingProfile *prof;
509 res = gst_encoding_target_new (targetname, categoryname, description, NULL);
511 /* Figure out the various profiles */
512 groups = g_key_file_get_groups (in, &nbgroups);
513 for (i = 0; i < nbgroups; i++) {
514 if (!g_ascii_strncasecmp (groups[i], "profile-", 8)) {
515 prof = parse_encoding_profile (in, NULL, groups[i], nbgroups, groups);
517 gst_encoding_target_add_profile (res, prof);
526 g_free (categoryname);
528 g_free (description);
534 load_file_and_read_header (const gchar * path, gchar ** targetname,
535 gchar ** categoryname, gchar ** description, GError ** error)
540 in = g_key_file_new ();
542 GST_DEBUG ("path:%s", path);
545 g_key_file_load_from_file (in, path,
546 G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, error);
547 if (!res || error != NULL)
551 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "name", error);
556 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "category", NULL);
558 g_key_file_get_value (in, GST_ENCODING_TARGET_HEADER, "description",
565 GST_WARNING ("Unable to read GstEncodingTarget file %s: %s",
566 path, (*error)->message);
567 g_key_file_free (in);
573 GST_WARNING ("Wrong header in file %s: %s", path, (*error)->message);
574 g_key_file_free (in);
580 * gst_encoding_target_load_from:
581 * @path: The file to load the #GstEncodingTarget from
582 * @error: If an error occured, this field will be filled in.
584 * Opens the provided file and returns the contained #GstEncodingTarget.
588 * Returns: The #GstEncodingTarget contained in the file, else %NULL
592 gst_encoding_target_load_from (const gchar * path, GError ** error)
595 gchar *targetname, *categoryname, *description;
596 GstEncodingTarget *res = NULL;
598 in = load_file_and_read_header (path, &targetname, &categoryname,
599 &description, error);
603 res = parse_keyfile (in, targetname, categoryname, description);
605 g_key_file_free (in);
612 * gst_encoding_target_load:
613 * @name: the name of the #GstEncodingTarget to load.
614 * @error: If an error occured, this field will be filled in.
616 * Searches for the #GstEncodingTarget with the given name, loads it
619 * Warning: NOT IMPLEMENTED.
623 * Returns: The #GstEncodingTarget if available, else %NULL
627 gst_encoding_target_load (const gchar * name, GError ** error)
629 /* FIXME : IMPLEMENT */
634 * gst_encoding_target_save:
635 * @target: a #GstEncodingTarget
636 * @error: If an error occured, this field will be filled in.
638 * Saves the @target to the default location.
640 * Warning: NOT IMPLEMENTED.
644 * Returns: %TRUE if the target was correctly saved, else %FALSE.
648 gst_encoding_target_save (GstEncodingTarget * target, GError ** error)
650 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
652 /* FIXME : IMPLEMENT */
657 * gst_encoding_target_save_to:
658 * @target: a #GstEncodingTarget
659 * @path: the location to store the @target at.
660 * @error: If an error occured, this field will be filled in.
662 * Saves the @target to the provided location.
666 * Returns: %TRUE if the target was correctly saved, else %FALSE.
670 gst_encoding_target_save_to (GstEncodingTarget * target, const gchar * path,
677 g_return_val_if_fail (GST_IS_ENCODING_TARGET (target), FALSE);
678 g_return_val_if_fail (path != NULL, FALSE);
680 /* FIXME : Check path is valid and writable
681 * FIXME : Strip out profiles already present in system target */
683 /* Get unique name... */
685 /* Create output GKeyFile */
686 out = g_key_file_new ();
688 if (!serialize_target (out, target))
689 goto serialize_failure;
691 if (!(data = g_key_file_to_data (out, &data_size, error)))
694 if (!g_file_set_contents (path, data, data_size, error))
697 g_key_file_free (out);
704 GST_ERROR ("Failure serializing target");
705 g_key_file_free (out);
711 GST_ERROR ("Failure converting keyfile: %s", (*error)->message);
712 g_key_file_free (out);
719 GST_ERROR ("Unable to write file %s: %s", path, (*error)->message);
720 g_key_file_free (out);