pbutils: Fix the documentation build warning.
[platform/upstream/gstreamer.git] / gst-libs / gst / pbutils / encoding-profile.c
1 /* GStreamer encoding profiles library
2  * Copyright (C) 2009-2010 Edward Hervey <edward.hervey@collabora.co.uk>
3  *           (C) 2009-2010 Nokia Corporation
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /**
22  * SECTION:encoding-profile
23  * @short_description: Encoding profile library
24  *
25  * <refsect2>
26  * <para>
27  * Functions to create and handle encoding profiles.
28  * </para>
29  * <para>
30  * Encoding profiles describe the media types and settings one wishes to use for
31  * an encoding process. The top-level profiles are commonly
32  * #GstEncodingContainerProfile(s) (which contains a user-readable name and
33  * description along with which container format to use). These, in turn,
34  * reference one or more #GstEncodingProfile(s) which indicate which encoding
35  * format should be used on each individual streams.
36  * </para>
37  * <para>
38  * #GstEncodingProfile(s) can be provided to the 'encodebin' element, which will take
39  * care of selecting and setting up the required elements to produce an output stream
40  * conforming to the specifications of the profile.
41  * </para>
42  * <para>
43  * Unlike other systems, the encoding profiles do not specify which #GstElement to use
44  * for the various encoding and muxing steps, but instead relies on specifying the format
45  * one wishes to use.
46  * </para>
47  * <para>
48  * Encoding profiles can be created at runtime by the application or loaded from (and saved
49  * to) file using the #GstEncodingTarget API.
50  * </para>
51  * </refsect2>
52  * <refsect2>
53  * <title>Example: Creating a profile</title>
54  * <para>
55  * |[
56  * #include <gst/pbutils/encoding-profile.h>
57  * ...
58  * GstEncodingProfile *
59  * create_ogg_theora_profile(void)
60  *{
61  *  GstEncodingContainerProfile *prof;
62  *  GstCaps *caps;
63  *
64  *  caps = gst_caps_from_string("application/ogg");
65  *  prof = gst_encoding_container_profile_new("Ogg audio/video",
66  *     "Standard OGG/THEORA/VORBIS",
67  *     caps, NULL);
68  *  gst_caps_unref (caps);
69  *
70  *  caps = gst_caps_from_string("video/x-theora");
71  *  gst_encoding_container_profile_add_profile(prof,
72  *       (GstEncodingProfile*) gst_encoding_video_profile_new(caps, NULL, NULL, 0));
73  *  gst_caps_unref (caps);
74  *
75  *  caps = gst_caps_from_string("audio/x-vorbis");
76  *  gst_encoding_container_profile_add_profile(prof,
77  *       (GstEncodingProfile*) gst_encoding_audio_profile_new(caps, NULL, NULL, 0));
78  *  gst_caps_unref (caps);
79  *
80  *  return (GstEncodingProfile*) prof;
81  *}
82  *
83  *
84  * ]|
85  * </para>
86  * </refsect2>
87  * <refsect2>
88  * <title>Example: Listing categories, targets and profiles</title>
89  * <para>
90  * |[
91  * #include <gst/pbutils/encoding-profile.h>
92  * ...
93  * GstEncodingProfile *prof;
94  * GList *categories, *tmpc;
95  * GList *targets, *tmpt;
96  * ...
97  * categories = gst_encoding_target_list_available_categories();
98  *
99  * ... Show available categories to user ...
100  *
101  * for (tmpc = categories; tmpc; tmpc = tmpc->next) {
102  *   gchar *category = (gchar *) tmpc->data;
103  *
104  *   ... and we can list all targets within that category ...
105  *
106  *   targets = gst_encoding_target_list_all (category);
107  *
108  *   ... and show a list to our users ...
109  *
110  *   g_list_foreach (targets, (GFunc) gst_encoding_target_unref, NULL);
111  *   g_list_free (targets);
112  * }
113  *
114  * g_list_foreach (categories, (GFunc) g_free, NULL);
115  * g_list_free (categories);
116  *
117  * ...
118  * ]|
119  * </para>
120  * </refsect2>
121  */
122
123 #ifdef HAVE_CONFIG_H
124 #  include "config.h"
125 #endif
126
127 #include "encoding-profile.h"
128 #include "encoding-target.h"
129
130 #include <string.h>
131
132 /* GstEncodingProfile API */
133
134 struct _GstEncodingProfile
135 {
136   GObject parent;
137
138   /*< public > */
139   gchar *name;
140   gchar *description;
141   GstCaps *format;
142   gchar *preset;
143   gchar *preset_name;
144   guint presence;
145   GstCaps *restriction;
146 };
147
148 struct _GstEncodingProfileClass
149 {
150   GObjectClass parent_class;
151 };
152
153 static void string_to_profile_transform (const GValue * src_value,
154     GValue * dest_value);
155 static gboolean gst_encoding_profile_deserialize_valfunc (GValue * value,
156     const gchar * s);
157
158 static void gst_encoding_profile_class_init (GstEncodingProfileClass * klass);
159 static gpointer gst_encoding_profile_parent_class = NULL;
160
161 static void
162 gst_encoding_profile_class_intern_init (gpointer klass)
163 {
164   gst_encoding_profile_parent_class = g_type_class_peek_parent (klass);
165   gst_encoding_profile_class_init ((GstEncodingProfileClass *) klass);
166 }
167
168 GType
169 gst_encoding_profile_get_type (void)
170 {
171   static volatile gsize g_define_type_id__volatile = 0;
172
173   if (g_once_init_enter (&g_define_type_id__volatile)) {
174     GType g_define_type_id = g_type_register_static_simple (G_TYPE_OBJECT,
175         g_intern_static_string ("GstEncodingProfile"),
176         sizeof (GstEncodingProfileClass),
177         (GClassInitFunc) gst_encoding_profile_class_intern_init,
178         sizeof (GstEncodingProfile),
179         NULL,
180         (GTypeFlags) 0);
181     static GstValueTable gstvtable = {
182       G_TYPE_NONE,
183       (GstValueCompareFunc) NULL,
184       (GstValueSerializeFunc) NULL,
185       (GstValueDeserializeFunc) gst_encoding_profile_deserialize_valfunc
186     };
187
188     gstvtable.type = g_define_type_id;
189
190     /* Register a STRING=>PROFILE GValueTransformFunc */
191     g_value_register_transform_func (G_TYPE_STRING, g_define_type_id,
192         string_to_profile_transform);
193     /* Register gst-specific GValue functions */
194     gst_value_register (&gstvtable);
195
196     g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
197   }
198   return g_define_type_id__volatile;
199 }
200
201 static void
202 gst_encoding_profile_finalize (GObject * object)
203 {
204   GstEncodingProfile *prof = (GstEncodingProfile *) object;
205   if (prof->name)
206     g_free (prof->name);
207   if (prof->format)
208     gst_caps_unref (prof->format);
209   if (prof->preset)
210     g_free (prof->preset);
211   if (prof->description)
212     g_free (prof->description);
213   if (prof->restriction)
214     gst_caps_unref (prof->restriction);
215 }
216
217 static void
218 gst_encoding_profile_class_init (GstEncodingProfileClass * klass)
219 {
220   GObjectClass *gobject_class = (GObjectClass *) klass;
221
222   gobject_class->finalize = gst_encoding_profile_finalize;
223 }
224
225 /**
226  * gst_encoding_profile_get_name:
227  * @profile: a #GstEncodingProfile
228  *
229  * Returns: the name of the profile, can be %NULL.
230  */
231 const gchar *
232 gst_encoding_profile_get_name (GstEncodingProfile * profile)
233 {
234   return profile->name;
235 }
236
237 /**
238  * gst_encoding_profile_get_description:
239  * @profile: a #GstEncodingProfile
240  *
241  * Returns: the description of the profile, can be %NULL.
242  */
243 const gchar *
244 gst_encoding_profile_get_description (GstEncodingProfile * profile)
245 {
246   return profile->description;
247 }
248
249 /**
250  * gst_encoding_profile_get_format:
251  * @profile: a #GstEncodingProfile
252  *
253  * Returns: (transfer full): the #GstCaps corresponding to the media format used
254  * in the profile. Unref after usage.
255  */
256 GstCaps *
257 gst_encoding_profile_get_format (GstEncodingProfile * profile)
258 {
259   return (profile->format ? gst_caps_ref (profile->format) : NULL);
260 }
261
262 /**
263  * gst_encoding_profile_get_preset:
264  * @profile: a #GstEncodingProfile
265  *
266  * Returns: the name of the #GstPreset to be used in the profile.
267  * This is the name that has been set when saving the preset.
268  */
269 const gchar *
270 gst_encoding_profile_get_preset (GstEncodingProfile * profile)
271 {
272   return profile->preset;
273 }
274
275 /**
276  * gst_encoding_profile_get_preset_name:
277  * @profile: a #GstEncodingProfile
278  *
279  * Returns: the name of the #GstPreset factory to be used in the profile.
280  */
281 const gchar *
282 gst_encoding_profile_get_preset_name (GstEncodingProfile * profile)
283 {
284   return profile->preset_name;
285 }
286
287 /**
288  * gst_encoding_profile_get_presence:
289  * @profile: a #GstEncodingProfile
290  *
291  * Returns: The number of times the profile is used in its parent
292  * container profile. If 0, it is not a mandatory stream.
293  */
294 guint
295 gst_encoding_profile_get_presence (GstEncodingProfile * profile)
296 {
297   return profile->presence;
298 }
299
300 /**
301  * gst_encoding_profile_get_restriction:
302  * @profile: a #GstEncodingProfile
303  *
304  * Returns: (transfer full): The restriction #GstCaps to apply before the encoder
305  * that will be used in the profile. The fields present in restriction caps are
306  * properties of the raw stream (that is before encoding), such as height and
307  * width for video and depth and sampling rate for audio. Does not apply to
308  * #GstEncodingContainerProfile (since there is no corresponding raw stream).
309  * Can be %NULL. Unref after usage.
310  */
311 GstCaps *
312 gst_encoding_profile_get_restriction (GstEncodingProfile * profile)
313 {
314   return (profile->restriction ? gst_caps_ref (profile->restriction) : NULL);
315 }
316
317 /**
318  * gst_encoding_profile_set_name:
319  * @profile: a #GstEncodingProfile
320  * @name: the name to set on the profile
321  *
322  * Set @name as the given name for the @profile. A copy of @name will be made
323  * internally.
324  */
325 void
326 gst_encoding_profile_set_name (GstEncodingProfile * profile, const gchar * name)
327 {
328   if (profile->name)
329     g_free (profile->name);
330   profile->name = g_strdup (name);
331 }
332
333 /**
334  * gst_encoding_profile_set_description:
335  * @profile: a #GstEncodingProfile
336  * @description: the description to set on the profile
337  *
338  * Set @description as the given description for the @profile. A copy of
339  * @description will be made internally.
340  */
341 void
342 gst_encoding_profile_set_description (GstEncodingProfile * profile,
343     const gchar * description)
344 {
345   if (profile->description)
346     g_free (profile->description);
347   profile->description = g_strdup (description);
348 }
349
350 /**
351  * gst_encoding_profile_set_format:
352  * @profile: a #GstEncodingProfile
353  * @format: the media format to use in the profile.
354  *
355  * Sets the media format used in the profile.
356  */
357 void
358 gst_encoding_profile_set_format (GstEncodingProfile * profile, GstCaps * format)
359 {
360   if (profile->format)
361     gst_caps_unref (profile->format);
362   profile->format = gst_caps_ref (format);
363 }
364
365 /**
366  * gst_encoding_profile_set_preset:
367  * @profile: a #GstEncodingProfile
368  * @preset: the element preset to use
369  *
370  * Sets the name of the #GstElement that implements the #GstPreset interface
371  * to use for the profile.
372  * This is the name that has been set when saving the preset.
373  */
374 void
375 gst_encoding_profile_set_preset (GstEncodingProfile * profile,
376     const gchar * preset)
377 {
378   if (profile->preset)
379     g_free (profile->preset);
380   profile->preset = g_strdup (preset);
381 }
382
383 /**
384  * gst_encoding_profile_set_preset_name:
385  * @profile: a #GstEncodingProfile
386  * @preset_name: The name of the preset to use in this @profile.
387  *
388  * Sets the name of the #GstPreset's factory to be used in the profile.
389  */
390 void
391 gst_encoding_profile_set_preset_name (GstEncodingProfile * profile,
392     const gchar * preset_name)
393 {
394   if (profile->preset_name)
395     g_free (profile->preset_name);
396   profile->preset_name = g_strdup (preset_name);
397 }
398
399 /**
400  * gst_encoding_profile_set_presence:
401  * @profile: a #GstEncodingProfile
402  * @presence: the number of time the profile can be used
403  *
404  * Set the number of time the profile is used in its parent
405  * container profile. If 0, it is not a mandatory stream
406  */
407 void
408 gst_encoding_profile_set_presence (GstEncodingProfile * profile, guint presence)
409 {
410   profile->presence = presence;
411 }
412
413 /**
414  * gst_encoding_profile_set_restriction:
415  * @profile: a #GstEncodingProfile
416  * @restriction: (transfer full): the restriction to apply
417  *
418  * Set the restriction #GstCaps to apply before the encoder
419  * that will be used in the profile. See gst_encoding_profile_set_restriction()
420  * for more about restrictions. Does not apply to #GstEncodingContainerProfile.
421  */
422 void
423 gst_encoding_profile_set_restriction (GstEncodingProfile * profile,
424     GstCaps * restriction)
425 {
426   if (profile->restriction)
427     gst_caps_unref (profile->restriction);
428   profile->restriction = restriction;
429 }
430
431 /* Container profiles */
432
433 struct _GstEncodingContainerProfile
434 {
435   GstEncodingProfile parent;
436
437   GList *encodingprofiles;
438 };
439
440 struct _GstEncodingContainerProfileClass
441 {
442   GstEncodingProfileClass parent;
443 };
444
445 G_DEFINE_TYPE (GstEncodingContainerProfile, gst_encoding_container_profile,
446     GST_TYPE_ENCODING_PROFILE);
447
448 static void
449 gst_encoding_container_profile_init (GstEncodingContainerProfile * prof)
450 {
451   /* Nothing to initialize */
452 }
453
454 static void
455 gst_encoding_container_profile_finalize (GObject * object)
456 {
457   GstEncodingContainerProfile *prof = (GstEncodingContainerProfile *) object;
458
459   g_list_foreach (prof->encodingprofiles, (GFunc) g_object_unref, NULL);
460   g_list_free (prof->encodingprofiles);
461
462   G_OBJECT_CLASS (gst_encoding_container_profile_parent_class)->finalize
463       ((GObject *) prof);
464 }
465
466 static void
467 gst_encoding_container_profile_class_init (GstEncodingContainerProfileClass * k)
468 {
469   GObjectClass *gobject_class = (GObjectClass *) k;
470
471   gobject_class->finalize = gst_encoding_container_profile_finalize;
472 }
473
474 /**
475  * gst_encoding_container_profile_get_profiles:
476  * @profile: a #GstEncodingContainerProfile
477  *
478  * Returns: (element-type GstPbutils.EncodingProfile) (transfer none):
479  * the list of contained #GstEncodingProfile.
480  */
481 const GList *
482 gst_encoding_container_profile_get_profiles (GstEncodingContainerProfile *
483     profile)
484 {
485   return profile->encodingprofiles;
486 }
487
488 /* Video profiles */
489
490 struct _GstEncodingVideoProfile
491 {
492   GstEncodingProfile parent;
493
494   guint pass;
495   gboolean variableframerate;
496 };
497
498 struct _GstEncodingVideoProfileClass
499 {
500   GstEncodingProfileClass parent;
501 };
502
503 G_DEFINE_TYPE (GstEncodingVideoProfile, gst_encoding_video_profile,
504     GST_TYPE_ENCODING_PROFILE);
505
506 static void
507 gst_encoding_video_profile_init (GstEncodingVideoProfile * prof)
508 {
509   /* Nothing to initialize */
510 }
511
512 static void
513 gst_encoding_video_profile_class_init (GstEncodingVideoProfileClass * klass)
514 {
515 }
516
517 /**
518  * gst_encoding_video_profile_get_pass:
519  * @prof: a #GstEncodingVideoProfile
520  *
521  * Get the pass number if this is part of a multi-pass profile.
522  *
523  * Returns: The pass number. Starts at 1 for multi-pass. 0 if this is
524  * not a multi-pass profile
525  */
526 guint
527 gst_encoding_video_profile_get_pass (GstEncodingVideoProfile * prof)
528 {
529   return prof->pass;
530 }
531
532 /**
533  * gst_encoding_video_profile_get_variableframerate:
534  * @prof: a #GstEncodingVideoProfile
535  *
536  * Returns: Whether non-constant video framerate is allowed for encoding.
537  */
538 gboolean
539 gst_encoding_video_profile_get_variableframerate (GstEncodingVideoProfile *
540     prof)
541 {
542   return prof->variableframerate;
543 }
544
545 /**
546  * gst_encoding_video_profile_set_pass:
547  * @prof: a #GstEncodingVideoProfile
548  * @pass: the pass number for this profile
549  *
550  * Sets the pass number of this video profile. The first pass profile should have
551  * this value set to 1. If this video profile isn't part of a multi-pass profile,
552  * you may set it to 0 (the default value).
553  */
554 void
555 gst_encoding_video_profile_set_pass (GstEncodingVideoProfile * prof, guint pass)
556 {
557   prof->pass = pass;
558 }
559
560 /**
561  * gst_encoding_video_profile_set_variableframerate:
562  * @prof: a #GstEncodingVideoProfile
563  * @variableframerate: a boolean
564  *
565  * If set to %TRUE, then the incoming stream will be allowed to have non-constant
566  * framerate. If set to %FALSE (default value), then the incoming stream will
567  * be normalized by dropping/duplicating frames in order to produce a
568  * constance framerate.
569  */
570 void
571 gst_encoding_video_profile_set_variableframerate (GstEncodingVideoProfile *
572     prof, gboolean variableframerate)
573 {
574   prof->variableframerate = variableframerate;
575 }
576
577 /* Audio profiles */
578
579 struct _GstEncodingAudioProfile
580 {
581   GstEncodingProfile parent;
582 };
583
584 struct _GstEncodingAudioProfileClass
585 {
586   GstEncodingProfileClass parent;
587 };
588
589 G_DEFINE_TYPE (GstEncodingAudioProfile, gst_encoding_audio_profile,
590     GST_TYPE_ENCODING_PROFILE);
591
592 static void
593 gst_encoding_audio_profile_init (GstEncodingAudioProfile * prof)
594 {
595   /* Nothing to initialize */
596 }
597
598 static void
599 gst_encoding_audio_profile_class_init (GstEncodingAudioProfileClass * klass)
600 {
601 }
602
603 static inline gboolean
604 _gst_caps_is_equal_safe (GstCaps * a, GstCaps * b)
605 {
606   if (a == b)
607     return TRUE;
608   if ((a == NULL) || (b == NULL))
609     return FALSE;
610   return gst_caps_is_equal (a, b);
611 }
612
613 static gint
614 _compare_container_encoding_profiles (GstEncodingContainerProfile * ca,
615     GstEncodingContainerProfile * cb)
616 {
617   GList *tmp;
618
619   if (g_list_length (ca->encodingprofiles) !=
620       g_list_length (cb->encodingprofiles))
621     return -1;
622
623   for (tmp = ca->encodingprofiles; tmp; tmp = tmp->next) {
624     GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
625     if (!gst_encoding_container_profile_contains_profile (ca, prof))
626       return -1;
627   }
628
629   return 0;
630 }
631
632 static gint
633 _compare_encoding_profiles (const GstEncodingProfile * a,
634     const GstEncodingProfile * b)
635 {
636   if ((G_TYPE_FROM_INSTANCE (a) != G_TYPE_FROM_INSTANCE (b)) ||
637       !_gst_caps_is_equal_safe (a->format, b->format) ||
638       (g_strcmp0 (a->preset, b->preset) != 0) ||
639       (g_strcmp0 (a->name, b->name) != 0) ||
640       (g_strcmp0 (a->description, b->description) != 0))
641     return -1;
642
643   if (GST_IS_ENCODING_CONTAINER_PROFILE (a))
644     return
645         _compare_container_encoding_profiles (GST_ENCODING_CONTAINER_PROFILE
646         (a), GST_ENCODING_CONTAINER_PROFILE (b));
647
648   if (GST_IS_ENCODING_VIDEO_PROFILE (a)) {
649     GstEncodingVideoProfile *va = (GstEncodingVideoProfile *) a;
650     GstEncodingVideoProfile *vb = (GstEncodingVideoProfile *) b;
651
652     if ((va->pass != vb->pass)
653         || (va->variableframerate != vb->variableframerate))
654       return -1;
655   }
656
657   return 0;
658 }
659
660 /**
661  * gst_encoding_container_profile_contains_profile:
662  * @container: a #GstEncodingContainerProfile
663  * @profile: a #GstEncodingProfile
664  *
665  * Checks if @container contains a #GstEncodingProfile identical to
666  * @profile.
667  *
668  * Returns: %TRUE if @container contains a #GstEncodingProfile identical
669  * to @profile, else %FALSE.
670  */
671 gboolean
672 gst_encoding_container_profile_contains_profile (GstEncodingContainerProfile *
673     container, GstEncodingProfile * profile)
674 {
675   g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE);
676   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
677
678   return (g_list_find_custom (container->encodingprofiles, profile,
679           (GCompareFunc) _compare_encoding_profiles) != NULL);
680 }
681
682 /**
683  * gst_encoding_container_profile_add_profile:
684  * @container: the #GstEncodingContainerProfile to use
685  * @profile: (transfer full): the #GstEncodingProfile to add.
686  *
687  * Add a #GstEncodingProfile to the list of profiles handled by @container.
688  *
689  * No copy of @profile will be made, if you wish to use it elsewhere after this
690  * method you should increment its reference count.
691  *
692  * Returns: %TRUE if the @stream was properly added, else %FALSE.
693  */
694 gboolean
695 gst_encoding_container_profile_add_profile (GstEncodingContainerProfile *
696     container, GstEncodingProfile * profile)
697 {
698   g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE);
699   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
700
701   if (g_list_find_custom (container->encodingprofiles, profile,
702           (GCompareFunc) _compare_encoding_profiles)) {
703     GST_ERROR
704         ("Encoding profile already contains an identical GstEncodingProfile");
705     return FALSE;
706   }
707
708   container->encodingprofiles =
709       g_list_append (container->encodingprofiles, profile);
710
711   return TRUE;
712 }
713
714 static GstEncodingProfile *
715 common_creation (GType objtype, GstCaps * format, const gchar * preset,
716     const gchar * name, const gchar * description, GstCaps * restriction,
717     guint presence)
718 {
719   GstEncodingProfile *prof;
720
721   prof = (GstEncodingProfile *) g_object_new (objtype, NULL);
722
723   if (name)
724     prof->name = g_strdup (name);
725   if (description)
726     prof->description = g_strdup (description);
727   if (preset)
728     prof->preset = g_strdup (preset);
729   if (format)
730     prof->format = gst_caps_ref (format);
731   if (restriction)
732     prof->restriction = gst_caps_ref (restriction);
733   prof->presence = presence;
734   prof->preset_name = NULL;
735
736   return prof;
737 }
738
739 /**
740  * gst_encoding_container_profile_new:
741  * @name: (allow-none): The name of the container profile, can be %NULL
742  * @description: (allow-none): The description of the container profile,
743  *     can be %NULL
744  * @format: The format to use for this profile
745  * @preset: (allow-none): The preset to use for this profile.
746  *
747  * Creates a new #GstEncodingContainerProfile.
748  *
749  * Returns: The newly created #GstEncodingContainerProfile.
750  */
751 GstEncodingContainerProfile *
752 gst_encoding_container_profile_new (const gchar * name,
753     const gchar * description, GstCaps * format, const gchar * preset)
754 {
755   g_return_val_if_fail (GST_IS_CAPS (format), NULL);
756
757   return (GstEncodingContainerProfile *)
758       common_creation (GST_TYPE_ENCODING_CONTAINER_PROFILE, format, preset,
759       name, description, NULL, 0);
760 }
761
762 /**
763  * gst_encoding_video_profile_new:
764  * @format: the #GstCaps
765  * @preset: (allow-none): the preset(s) to use on the encoder, can be #NULL
766  * @restriction: (allow-none): the #GstCaps used to restrict the input to the encoder, can be
767  * NULL. See gst_encoding_profile_get_restriction() for more details.
768  * @presence: the number of time this stream must be used. 0 means any number of
769  *  times (including never)
770  *
771  * Creates a new #GstEncodingVideoProfile
772  *
773  * All provided allocatable arguments will be internally copied, so can be
774  * safely freed/unreferenced after calling this method.
775  *
776  * If you wish to control the pass number (in case of multi-pass scenarios),
777  * please refer to the gst_encoding_video_profile_set_pass() documentation.
778  *
779  * If you wish to use/force a constant framerate please refer to the
780  * gst_encoding_video_profile_set_variableframerate() documentation.
781  *
782  * Returns: the newly created #GstEncodingVideoProfile.
783  */
784 GstEncodingVideoProfile *
785 gst_encoding_video_profile_new (GstCaps * format, const gchar * preset,
786     GstCaps * restriction, guint presence)
787 {
788   return (GstEncodingVideoProfile *)
789       common_creation (GST_TYPE_ENCODING_VIDEO_PROFILE, format, preset, NULL,
790       NULL, restriction, presence);
791 }
792
793 /**
794  * gst_encoding_audio_profile_new:
795  * @format: the #GstCaps
796  * @preset: (allow-none): the preset(s) to use on the encoder, can be #NULL
797  * @restriction: (allow-none): the #GstCaps used to restrict the input to the encoder, can be
798  * NULL. See gst_encoding_profile_get_restriction() for more details.
799  * @presence: the number of time this stream must be used. 0 means any number of
800  *  times (including never)
801  *
802  * Creates a new #GstEncodingAudioProfile
803  *
804  * All provided allocatable arguments will be internally copied, so can be
805  * safely freed/unreferenced after calling this method.
806  *
807  * Returns: the newly created #GstEncodingAudioProfile.
808  */
809 GstEncodingAudioProfile *
810 gst_encoding_audio_profile_new (GstCaps * format, const gchar * preset,
811     GstCaps * restriction, guint presence)
812 {
813   return (GstEncodingAudioProfile *)
814       common_creation (GST_TYPE_ENCODING_AUDIO_PROFILE, format, preset, NULL,
815       NULL, restriction, presence);
816 }
817
818
819 /**
820  * gst_encoding_profile_is_equal:
821  * @a: a #GstEncodingProfile
822  * @b: a #GstEncodingProfile
823  *
824  * Checks whether the two #GstEncodingProfile are equal
825  *
826  * Returns: %TRUE if @a and @b are equal, else %FALSE.
827  */
828 gboolean
829 gst_encoding_profile_is_equal (GstEncodingProfile * a, GstEncodingProfile * b)
830 {
831   return (_compare_encoding_profiles (a, b) == 0);
832 }
833
834
835 /**
836  * gst_encoding_profile_get_input_caps:
837  * @profile: a #GstEncodingProfile
838  *
839  * Computes the full output caps that this @profile will be able to consume.
840  *
841  * Returns: (transfer full): The full caps the given @profile can consume. Call
842  * gst_caps_unref() when you are done with the caps.
843  */
844 GstCaps *
845 gst_encoding_profile_get_input_caps (GstEncodingProfile * profile)
846 {
847   GstCaps *out, *tmp;
848   GList *ltmp;
849   GstStructure *st, *outst;
850   GQuark out_name;
851   guint i, len;
852   GstCaps *fcaps;
853
854   if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
855     GstCaps *res = gst_caps_new_empty ();
856
857     for (ltmp = GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles;
858         ltmp; ltmp = ltmp->next) {
859       GstEncodingProfile *sprof = (GstEncodingProfile *) ltmp->data;
860       res = gst_caps_merge (res, gst_encoding_profile_get_input_caps (sprof));
861     }
862     return res;
863   }
864
865   fcaps = profile->format;
866
867   /* fast-path */
868   if ((profile->restriction == NULL) || gst_caps_is_any (profile->restriction))
869     return gst_caps_ref (fcaps);
870
871   /* Combine the format with the restriction caps */
872   outst = gst_caps_get_structure (fcaps, 0);
873   out_name = gst_structure_get_name_id (outst);
874   tmp = gst_caps_new_empty ();
875   len = gst_caps_get_size (profile->restriction);
876
877   for (i = 0; i < len; i++) {
878     st = gst_structure_copy (gst_caps_get_structure (profile->restriction, i));
879     st->name = out_name;
880     gst_caps_append_structure (tmp, st);
881   }
882
883   out = gst_caps_intersect (tmp, fcaps);
884   gst_caps_unref (tmp);
885
886   return out;
887 }
888
889 /**
890  * gst_encoding_profile_get_type_nick:
891  * @profile: a #GstEncodingProfile
892  *
893  * Returns: the human-readable name of the type of @profile.
894  */
895 const gchar *
896 gst_encoding_profile_get_type_nick (GstEncodingProfile * profile)
897 {
898   if (GST_IS_ENCODING_CONTAINER_PROFILE (profile))
899     return "container";
900   if (GST_IS_ENCODING_VIDEO_PROFILE (profile))
901     return "video";
902   if (GST_IS_ENCODING_AUDIO_PROFILE (profile))
903     return "audio";
904   return NULL;
905 }
906
907 extern const gchar *pb_utils_get_file_extension_from_caps (const GstCaps *
908     caps);
909 gboolean pb_utils_is_tag (const GstCaps * caps);
910
911 static gboolean
912 gst_encoding_profile_has_format (GstEncodingProfile * profile,
913     const gchar * media_type)
914 {
915   GstCaps *caps;
916   gboolean ret;
917
918   caps = gst_encoding_profile_get_format (profile);
919   ret = gst_structure_has_name (gst_caps_get_structure (caps, 0), media_type);
920   gst_caps_unref (caps);
921
922   return ret;
923 }
924
925 static gboolean
926 gst_encoding_container_profile_has_video (GstEncodingContainerProfile * profile)
927 {
928   const GList *l;
929
930   for (l = profile->encodingprofiles; l != NULL; l = l->next) {
931     if (GST_IS_ENCODING_VIDEO_PROFILE (l->data))
932       return TRUE;
933     if (GST_IS_ENCODING_CONTAINER_PROFILE (l->data) &&
934         gst_encoding_container_profile_has_video (l->data))
935       return TRUE;
936   }
937
938   return FALSE;
939 }
940
941 /**
942  * gst_encoding_profile_get_file_extension:
943  * @profile: a #GstEncodingProfile
944  *
945  * Returns: a suitable file extension for @profile, or NULL.
946  */
947 const gchar *
948 gst_encoding_profile_get_file_extension (GstEncodingProfile * profile)
949 {
950   GstEncodingContainerProfile *cprofile;
951   const gchar *ext = NULL;
952   gboolean has_video;
953   GstCaps *caps;
954   guint num_children;
955
956   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
957
958   caps = gst_encoding_profile_get_format (profile);
959   ext = pb_utils_get_file_extension_from_caps (caps);
960
961   if (!GST_IS_ENCODING_CONTAINER_PROFILE (profile))
962     goto done;
963
964   cprofile = GST_ENCODING_CONTAINER_PROFILE (profile);
965
966   num_children = g_list_length (cprofile->encodingprofiles);
967
968   /* if it's a tag container profile (e.g. id3mux/apemux), we need
969    * to look at what's inside it */
970   if (pb_utils_is_tag (caps)) {
971     GST_DEBUG ("tag container profile");
972     if (num_children == 1) {
973       GstEncodingProfile *child_profile = cprofile->encodingprofiles->data;
974
975       ext = gst_encoding_profile_get_file_extension (child_profile);
976     } else {
977       GST_WARNING ("expected exactly one child profile with tag profile");
978     }
979     goto done;
980   }
981
982   if (num_children == 0)
983     goto done;
984
985   /* special cases */
986   has_video = gst_encoding_container_profile_has_video (cprofile);
987
988   /* Ogg */
989   if (strcmp (ext, "ogg") == 0) {
990     /* ogg with video => .ogv */
991     if (has_video) {
992       ext = "ogv";
993       goto done;
994     }
995     /* ogg with just speex audio => .spx */
996     if (num_children == 1) {
997       GstEncodingProfile *child_profile = cprofile->encodingprofiles->data;
998
999       if (GST_IS_ENCODING_AUDIO_PROFILE (child_profile) &&
1000           gst_encoding_profile_has_format (child_profile, "audio/x-speex")) {
1001         ext = "spx";
1002         goto done;
1003       }
1004     }
1005     /* does anyone actually use .oga for ogg audio files? */
1006     goto done;
1007   }
1008
1009   /* Matroska */
1010   if (has_video && strcmp (ext, "mka") == 0) {
1011     ext = "mkv";
1012     goto done;
1013   }
1014
1015   /* Windows Media / ASF */
1016   if (gst_encoding_profile_has_format (profile, "video/x-ms-asf")) {
1017     const GList *l;
1018     guint num_wmv = 0, num_wma = 0, num_other = 0;
1019
1020     for (l = cprofile->encodingprofiles; l != NULL; l = l->next) {
1021       if (gst_encoding_profile_has_format (l->data, "video/x-wmv"))
1022         ++num_wmv;
1023       else if (gst_encoding_profile_has_format (l->data, "audio/x-wma"))
1024         ++num_wma;
1025       else
1026         ++num_other;
1027     }
1028
1029     if (num_other > 0)
1030       ext = "asf";
1031     else if (num_wmv > 0)
1032       ext = "wmv";
1033     else if (num_wma > 0)
1034       ext = "wma";
1035
1036     goto done;
1037   }
1038
1039 done:
1040
1041   GST_INFO ("caps %" GST_PTR_FORMAT ", ext: %s", caps, GST_STR_NULL (ext));
1042   gst_caps_unref (caps);
1043   return ext;
1044 }
1045
1046 /**
1047  * gst_encoding_profile_find:
1048  * @targetname: (transfer none): The name of the target
1049  * @profilename: (transfer none): The name of the profile
1050  * @category: (transfer none) (allow-none): The target category. Can be %NULL
1051  *
1052  * Find the #GstEncodingProfile with the specified name and category.
1053  *
1054  * Returns: (transfer full): The matching #GstEncodingProfile or %NULL.
1055  */
1056 GstEncodingProfile *
1057 gst_encoding_profile_find (const gchar * targetname, const gchar * profilename,
1058     const gchar * category)
1059 {
1060   GstEncodingProfile *res = NULL;
1061   GstEncodingTarget *target;
1062
1063   g_return_val_if_fail (targetname != NULL, NULL);
1064   g_return_val_if_fail (profilename != NULL, NULL);
1065
1066   /* FIXME : how do we handle profiles named the same in several
1067    * categories but of which only one has the required profile ? */
1068   target = gst_encoding_target_load (targetname, category, NULL);
1069   if (target) {
1070     res = gst_encoding_target_get_profile (target, profilename);
1071     gst_encoding_target_unref (target);
1072   }
1073
1074   return res;
1075 }
1076
1077 static GstEncodingProfile *
1078 combo_search (const gchar * pname)
1079 {
1080   GstEncodingProfile *res;
1081   gchar **split;
1082
1083   /* Splitup */
1084   split = g_strsplit (pname, "/", 2);
1085   if (g_strv_length (split) != 2)
1086     return NULL;
1087
1088   res = gst_encoding_profile_find (split[0], split[1], NULL);
1089
1090   g_strfreev (split);
1091
1092   return res;
1093 }
1094
1095 /* GValue transform function */
1096 static void
1097 string_to_profile_transform (const GValue * src_value, GValue * dest_value)
1098 {
1099   const gchar *profilename;
1100   GstEncodingProfile *profile;
1101
1102   profilename = g_value_get_string (src_value);
1103
1104   profile = combo_search (profilename);
1105
1106   if (profile)
1107     g_value_take_object (dest_value, (GObject *) profile);
1108 }
1109
1110 static gboolean
1111 gst_encoding_profile_deserialize_valfunc (GValue * value, const gchar * s)
1112 {
1113   GstEncodingProfile *profile;
1114
1115   profile = combo_search (s);
1116
1117   if (profile) {
1118     g_value_take_object (value, (GObject *) profile);
1119     return TRUE;
1120   }
1121
1122   return FALSE;
1123 }
1124
1125 /**
1126  * gst_encoding_profile_from_discoverer:
1127  * @info: (transfer none): The #GstDiscovererInfo to read from
1128  *
1129  * Creates a #GstEncodingProfile matching the formats from the given
1130  * #GstEncodingProfile. Streams other than audio or video (eg,
1131  * subtitles), are currently ignored.
1132  *
1133  * Returns: (transfer full): The new #GstEncodingProfile or %NULL.
1134  */
1135 GstEncodingProfile *
1136 gst_encoding_profile_from_discoverer (GstDiscovererInfo * info)
1137 {
1138   GstEncodingContainerProfile *profile;
1139   GstDiscovererStreamInfo *sinfo;
1140   GList *streams, *stream;
1141   GstCaps *caps = NULL;
1142
1143   if (!info || gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK)
1144     return NULL;
1145
1146   sinfo = gst_discoverer_info_get_stream_info (info);
1147   if (!sinfo)
1148     return NULL;
1149
1150   caps = gst_discoverer_stream_info_get_caps (sinfo);
1151   GST_LOG ("Container: %" GST_PTR_FORMAT "\n", caps);
1152   profile =
1153       gst_encoding_container_profile_new ("auto-generated",
1154       "Automatically generated from GstDiscovererInfo", caps, NULL);
1155   gst_caps_unref (caps);
1156   if (!profile) {
1157     GST_ERROR ("Failed to create container profile from caps %" GST_PTR_FORMAT,
1158         caps);
1159     return NULL;
1160   }
1161
1162   streams =
1163       gst_discoverer_container_info_get_streams (GST_DISCOVERER_CONTAINER_INFO
1164       (sinfo));
1165   for (stream = streams; stream; stream = stream->next) {
1166     GstEncodingProfile *sprofile = NULL;
1167     sinfo = (GstDiscovererStreamInfo *) stream->data;
1168     caps = gst_discoverer_stream_info_get_caps (sinfo);
1169     GST_LOG ("Stream: %" GST_PTR_FORMAT "\n", caps);
1170     if (GST_IS_DISCOVERER_AUDIO_INFO (sinfo)) {
1171       sprofile =
1172           (GstEncodingProfile *) gst_encoding_audio_profile_new (caps, NULL,
1173           NULL, 0);
1174     } else if (GST_IS_DISCOVERER_VIDEO_INFO (sinfo)) {
1175       sprofile =
1176           (GstEncodingProfile *) gst_encoding_video_profile_new (caps, NULL,
1177           NULL, 0);
1178     } else {
1179       /* subtitles or other ? ignore for now */
1180     }
1181     if (sprofile)
1182       gst_encoding_container_profile_add_profile (profile, sprofile);
1183     else
1184       GST_ERROR ("Failed to create stream profile from caps %" GST_PTR_FORMAT,
1185           caps);
1186     gst_caps_unref (caps);
1187   }
1188   gst_discoverer_stream_info_list_free (streams);
1189
1190   return (GstEncodingProfile *) profile;
1191 }