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