pbutils: Add a pbutils debug category
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-base / 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  * @title: GstEncodingProfile
24  * @short_description: Encoding profile library
25  * @symbols:
26  * - GstEncodingProfile
27  * - GstEncodingContainerProfile
28  * - GstEncodingVideoProfile
29  * - GstEncodingAudioProfile
30  *
31  * Functions to create and handle encoding profiles.
32  *
33  * Encoding profiles describe the media types and settings one wishes to use for
34  * an encoding process. The top-level profiles are commonly
35  * #GstEncodingContainerProfile(s) (which contains a user-readable name and
36  * description along with which container format to use). These, in turn,
37  * reference one or more #GstEncodingProfile(s) which indicate which encoding
38  * format should be used on each individual streams.
39  *
40  * #GstEncodingProfile(s) can be provided to the 'encodebin' element, which will
41  * take care of selecting and setting up the required elements to produce an
42  * output stream conforming to the specifications of the profile.
43  *
44  * The encoding profiles do not necessarily specify which #GstElement to use for
45  * the various encoding and muxing steps, as they allow to specifying the format
46  * one wishes to use.
47  *
48  * Encoding profiles can be created at runtime by the application or loaded from
49  * (and saved to) file using the #GstEncodingTarget API.
50  *
51  * ## The encoding profile serialization format
52  *
53  * Encoding profiles can be serialized to be used in the command line tools or
54  * to set it on other other #GObject-s using #gst_util_set_object_arg for
55  * example.
56  *
57  * The serialization format aims at being simple to understand although flexible
58  * enough to describe any possible encoding profile. There are several ways to
59  * describe the profile depending on the context but the general idea is that it
60  * is a colon separated list of EncodingProfiles descriptions, the first one
61  * needs to describe a #GstEncodingContainerProfile and the following ones
62  * describe elementary streams.
63  *
64  * ### Using encoders and muxer element factory name
65  *
66  * ```
67  *   muxer_factory_name:video_encoder_factory_name:audio_encoder_factory_name
68  * ```
69  *
70  * For example to encode a stream into a WebM container, with an OGG audio
71  * stream and a VP8 video stream, the serialized #GstEncodingProfile looks like:
72  *
73  * ```
74  *   webmmux:vp8enc:vorbisenc
75  * ```
76  *
77  * ### Define the encoding profile in a generic way using caps:
78  *
79  * ```
80  *   muxer_source_caps:video_encoder_source_caps:audio_encoder_source_caps
81  * ```
82  *
83  * For example to encode a stream into a WebM container, with an OGG audio
84  * stream and a VP8 video stream, the serialized #GstEncodingProfile looks like:
85  *
86  * ```
87  *   video/webm:video/x-vp8:audio/x-vorbis
88  * ```
89  *
90  * It is possible to mix caps and element type names so you can specify a
91  * specific video encoder while using caps for other encoders/muxer.
92  *
93  * ### Using preset
94  *
95  * You can also set the preset name of the encoding profile using the
96  * caps+preset_name syntax as in:
97  *
98  * ```
99  *   video/webm:video/x-vp8+youtube-preset:audio/x-vorbis
100  * ```
101  *
102  * ### Setting properties on muxers or on the encoding profile itself
103  *
104  * Moreover, you can set the extra properties:
105  *
106  *  * `|element-properties,property1=true` (See
107  *    #gst_encoding_profile_set_element_properties)
108  *  * `|presence=true` (See See #gst_encoding_profile_get_presence)
109  *  * `|single-segment=true` (See #gst_encoding_profile_set_single_segment)
110  *  * `|single-segment=true` (See
111  *    #gst_encoding_video_profile_set_variableframerate)
112  *
113  * for example:
114  *
115  * ```
116  *   video/webm:video/x-vp8|presence=1|element-properties,target-bitrate=500000:audio/x-vorbis
117  * ```
118  *
119  * ### Enforcing properties to the stream itself (video size, number of audio channels, etc..)
120  *
121  * You can also use the `restriction_caps->encoded_format_caps` syntax to
122  * specify the restriction caps to be set on a #GstEncodingProfile
123  *
124  * It corresponds to the restriction #GstCaps to apply before the encoder that
125  * will be used in the profile (See #gst_encoding_profile_get_restriction). The
126  * fields present in restriction caps are properties of the raw stream (that is,
127  * before encoding), such as height and width for video and depth and sampling
128  * rate for audio. This property does not make sense for muxers. See
129  * #gst_encoding_profile_get_restriction for more details.
130  *
131  * To force a video stream to be encoded with a Full HD resolution (using WebM
132  * as the container format, VP8 as the video codec and Vorbis as the audio
133  * codec), you should use:
134  *
135  * ```
136  *   "video/webm:video/x-raw,width=1920,height=1080->video/x-vp8:audio/x-vorbis"
137  * ```
138  *
139  * > NOTE: Make sure to enclose into quotes to avoid '>' to be reinterpreted by
140  * > the shell.
141  *
142  * In the case you are specifying encoders directly, the following is also
143  * possible:
144  *
145  * ```
146  *   matroskamux:x264enc,width=1920,height=1080:audio/x-vorbis
147  * ```
148  *
149  * ## Some serialized encoding formats examples
150  *
151  * ### MP3 audio and H264 in MP4**
152  *
153  * ```
154  *   video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=1,layer=3
155  * ```
156  *
157  * ### Vorbis and theora in OGG
158  *
159  * ```
160  *   application/ogg:video/x-theora:audio/x-vorbis
161  * ```
162  *
163  * ### AC3 and H264 in MPEG-TS
164  *
165  * ```
166  *   video/mpegts:video/x-h264:audio/x-ac3
167  * ```
168  *
169  * ## Loading a profile from encoding targets
170  *
171  * Anywhere you have to use a string to define a #GstEncodingProfile, you
172  * can use load it from a #GstEncodingTarget using the following syntaxes:
173  *
174  * ```
175  *   target_name[/profilename/category]
176  * ```
177  *
178  * or
179  *
180  * ```
181  *   /path/to/target.gep:profilename
182  * ```
183  *
184  * ## Examples
185  *
186  * ### Creating a profile
187  *
188  * ``` c
189  * #include <gst/pbutils/encoding-profile.h>
190  * ...
191  * GstEncodingProfile *
192  * create_ogg_theora_profile(void)
193  *{
194  *  GstEncodingContainerProfile *prof;
195  *  GstCaps *caps;
196  *
197  *  caps = gst_caps_from_string("application/ogg");
198  *  prof = gst_encoding_container_profile_new("Ogg audio/video",
199  *     "Standard OGG/THEORA/VORBIS",
200  *     caps, NULL);
201  *  gst_caps_unref (caps);
202  *
203  *  caps = gst_caps_from_string("video/x-theora");
204  *  gst_encoding_container_profile_add_profile(prof,
205  *       (GstEncodingProfile*) gst_encoding_video_profile_new(caps, NULL, NULL, 0));
206  *  gst_caps_unref (caps);
207  *
208  *  caps = gst_caps_from_string("audio/x-vorbis");
209  *  gst_encoding_container_profile_add_profile(prof,
210  *       (GstEncodingProfile*) gst_encoding_audio_profile_new(caps, NULL, NULL, 0));
211  *  gst_caps_unref (caps);
212  *
213  *  return (GstEncodingProfile*) prof;
214  *}
215  *
216  * ```
217  *
218  * ### Example: Using an encoder preset with a profile
219  *
220  * ``` c
221  * #include <gst/pbutils/encoding-profile.h>
222  * ...
223  * GstEncodingProfile *
224  * create_ogg_theora_profile(void)
225  *{
226  *  GstEncodingVideoProfile *v;
227  *  GstEncodingAudioProfile *a;
228  *  GstEncodingContainerProfile *prof;
229  *  GstCaps *caps;
230  *  GstPreset *preset;
231  *
232  *  caps = gst_caps_from_string ("application/ogg");
233  *  prof = gst_encoding_container_profile_new ("Ogg audio/video",
234  *     "Standard OGG/THEORA/VORBIS",
235  *     caps, NULL);
236  *  gst_caps_unref (caps);
237  *
238  *  preset = GST_PRESET (gst_element_factory_make ("theoraenc", "theorapreset"));
239  *  g_object_set (preset, "bitrate", 1000, NULL);
240  *  // The preset will be saved on the filesystem,
241  *  // so try to use a descriptive name
242  *  gst_preset_save_preset (preset, "theora_bitrate_preset");
243  *  gst_object_unref (preset);
244  *
245  *  caps = gst_caps_from_string ("video/x-theora");
246  *  v = gst_encoding_video_profile_new (caps, "theora_bitrate_preset", NULL, 0);
247  *  gst_encoding_container_profile_add_profile (prof, (GstEncodingProfile*) v);
248  *  gst_caps_unref (caps);
249  *
250  *  caps = gst_caps_from_string ("audio/x-vorbis");
251  *  a = gst_encoding_audio_profile_new (caps, NULL, NULL, 0);
252  *  gst_encoding_container_profile_add_profile (prof, (GstEncodingProfile*) a);
253  *  gst_caps_unref (caps);
254  *
255  *  return (GstEncodingProfile*) prof;
256  *}
257  *
258  * ```
259  *
260  * ### Listing categories, targets and profiles
261  *
262  * ``` c
263  * #include <gst/pbutils/encoding-profile.h>
264  * ...
265  * GstEncodingProfile *prof;
266  * GList *categories, *tmpc;
267  * GList *targets, *tmpt;
268  * ...
269  * categories = gst_encoding_list_available_categories ();
270  *
271  * ... Show available categories to user ...
272  *
273  * for (tmpc = categories; tmpc; tmpc = tmpc->next) {
274  *   gchar *category = (gchar *) tmpc->data;
275  *
276  *   ... and we can list all targets within that category ...
277  *
278  *   targets = gst_encoding_list_all_targets (category);
279  *
280  *   ... and show a list to our users ...
281  *
282  *   g_list_foreach (targets, (GFunc) gst_encoding_target_unref, NULL);
283  *   g_list_free (targets);
284  * }
285  *
286  * g_list_foreach (categories, (GFunc) g_free, NULL);
287  * g_list_free (categories);
288  *
289  * ...
290  * ```
291  */
292
293 #ifdef HAVE_CONFIG_H
294 #  include "config.h"
295 #endif
296
297 #include "encoding-profile.h"
298 #include "encoding-target.h"
299
300 #include <string.h>
301
302 GST_DEBUG_CATEGORY_EXTERN (pbutils_debug);
303 #define GST_CAT_DEFAULT pbutils_debug
304
305 /* GstEncodingProfile API */
306 #define PROFILE_LOCK(profile) (g_mutex_lock(&((GstEncodingProfile*)profile)->lock))
307 #define PROFILE_UNLOCK(profile) (g_mutex_unlock(&((GstEncodingProfile*)profile)->lock))
308
309 struct _GstEncodingProfile
310 {
311   GObject parent;
312
313   /*< public > */
314   gchar *name;
315   gchar *description;
316   GstCaps *format;
317   gchar *preset;
318   gchar *preset_name;
319   guint presence;
320   gboolean allow_dynamic_output;
321   gboolean enabled;
322   gboolean single_segment;
323
324   GMutex lock;                  // {
325   GstCaps *restriction;
326   GstStructure *element_properties;
327   // }
328 };
329
330 struct _GstEncodingProfileClass
331 {
332   GObjectClass parent_class;
333
334   void (*copy) (GstEncodingProfile * self, GstEncodingProfile * copy);
335 };
336
337 enum
338 {
339   FIRST_PROPERTY,
340   PROP_RESTRICTION_CAPS,
341   PROP_ELEMENT_PROPERTIES,
342   LAST_PROPERTY
343 };
344
345 static GParamSpec *_properties[LAST_PROPERTY];
346
347 static void string_to_profile_transform (const GValue * src_value,
348     GValue * dest_value);
349 static gboolean gst_encoding_profile_deserialize_valfunc (GValue * value,
350     const gchar * s);
351 static gchar *gst_encoding_profile_serialize_valfunc (GValue * value);
352
353 static void gst_encoding_profile_class_init (GstEncodingProfileClass * klass);
354 static gpointer gst_encoding_profile_parent_class = NULL;
355
356 static void
357 gst_encoding_profile_class_intern_init (gpointer klass)
358 {
359   gst_encoding_profile_parent_class = g_type_class_peek_parent (klass);
360   gst_encoding_profile_class_init ((GstEncodingProfileClass *) klass);
361 }
362
363 GType
364 gst_encoding_profile_get_type (void)
365 {
366   static gsize g_define_type_id_init = 0;
367
368   if (g_once_init_enter (&g_define_type_id_init)) {
369     GType g_define_type_id = g_type_register_static_simple (G_TYPE_OBJECT,
370         g_intern_static_string ("GstEncodingProfile"),
371         sizeof (GstEncodingProfileClass),
372         (GClassInitFunc) gst_encoding_profile_class_intern_init,
373         sizeof (GstEncodingProfile),
374         NULL,
375         (GTypeFlags) 0);
376     static GstValueTable gstvtable = {
377       G_TYPE_NONE,
378       (GstValueCompareFunc) NULL,
379       (GstValueSerializeFunc) gst_encoding_profile_serialize_valfunc,
380       (GstValueDeserializeFunc) gst_encoding_profile_deserialize_valfunc
381     };
382
383     gstvtable.type = g_define_type_id;
384
385     /* Register a STRING=>PROFILE GValueTransformFunc */
386     g_value_register_transform_func (G_TYPE_STRING, g_define_type_id,
387         string_to_profile_transform);
388     /* Register gst-specific GValue functions */
389     gst_value_register (&gstvtable);
390
391     g_once_init_leave (&g_define_type_id_init, g_define_type_id);
392   }
393   return g_define_type_id_init;
394 }
395
396
397 static void
398 _encoding_profile_get_property (GObject * object, guint prop_id,
399     GValue * value, GParamSpec * pspec)
400 {
401   GstEncodingProfile *prof = (GstEncodingProfile *) object;
402
403   switch (prop_id) {
404     case PROP_RESTRICTION_CAPS:
405       gst_value_set_caps (value, prof->restriction);
406       break;
407     case PROP_ELEMENT_PROPERTIES:
408       PROFILE_LOCK (prof);
409       gst_value_set_structure (value, prof->element_properties);
410       PROFILE_UNLOCK (prof);
411       break;
412     default:
413       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
414       break;
415   }
416 }
417
418 static void
419 _encoding_profile_set_property (GObject * object, guint prop_id,
420     const GValue * value, GParamSpec * pspec)
421 {
422   GstEncodingProfile *prof = (GstEncodingProfile *) object;
423
424   switch (prop_id) {
425     case PROP_RESTRICTION_CAPS:
426       gst_encoding_profile_set_restriction (prof, gst_caps_copy
427           (gst_value_get_caps (value)));
428       break;
429     case PROP_ELEMENT_PROPERTIES:
430     {
431       const GstStructure *structure = gst_value_get_structure (value);
432
433       gst_encoding_profile_set_element_properties (prof,
434           structure ? gst_structure_copy (structure) : NULL);
435       break;
436     }
437     default:
438       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
439       break;
440   }
441 }
442
443 static void
444 gst_encoding_profile_finalize (GObject * object)
445 {
446   GstEncodingProfile *prof = (GstEncodingProfile *) object;
447   g_free (prof->name);
448   if (prof->format)
449     gst_caps_unref (prof->format);
450   g_free (prof->preset);
451   g_free (prof->description);
452   if (prof->restriction)
453     gst_caps_unref (prof->restriction);
454   g_free (prof->preset_name);
455 }
456
457 static void
458 gst_encoding_profile_class_init (GstEncodingProfileClass * klass)
459 {
460   GObjectClass *gobject_class = (GObjectClass *) klass;
461
462   gobject_class->finalize = gst_encoding_profile_finalize;
463
464   gobject_class->set_property = _encoding_profile_set_property;
465   gobject_class->get_property = _encoding_profile_get_property;
466
467   _properties[PROP_RESTRICTION_CAPS] =
468       g_param_spec_boxed ("restriction-caps", "Restriction caps",
469       "The restriction caps to use", GST_TYPE_CAPS,
470       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
471
472   /**
473    * GstEncodingProfile:element-properties:
474    *
475    * A #GstStructure defining the properties to be set to the element
476    * the profile represents.
477    *
478    * For example for `av1enc`:
479    *
480    * ```
481    * element-properties,row-mt=true, end-usage=vbr
482    * ```
483    *
484    * Since: 1.20
485    */
486   _properties[PROP_ELEMENT_PROPERTIES] =
487       g_param_spec_boxed ("element-properties", "Element properties",
488       "The element properties to use. "
489       "Example: {properties,boolean-prop=true,string-prop=\"hi\"}.",
490       GST_TYPE_STRUCTURE,
491       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
492
493   g_object_class_install_properties (gobject_class, LAST_PROPERTY, _properties);
494 }
495
496 /**
497  * gst_encoding_profile_get_name:
498  * @profile: a #GstEncodingProfile
499  *
500  * Returns: the name of the profile, can be %NULL.
501  */
502 const gchar *
503 gst_encoding_profile_get_name (GstEncodingProfile * profile)
504 {
505   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
506
507   return profile->name;
508 }
509
510 /**
511  * gst_encoding_profile_get_description:
512  * @profile: a #GstEncodingProfile
513  *
514  * Returns: the description of the profile, can be %NULL.
515  */
516 const gchar *
517 gst_encoding_profile_get_description (GstEncodingProfile * profile)
518 {
519   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
520
521   return profile->description;
522 }
523
524 /**
525  * gst_encoding_profile_get_format:
526  * @profile: a #GstEncodingProfile
527  *
528  * Returns: (transfer full): the #GstCaps corresponding to the media format used
529  * in the profile. Unref after usage.
530  */
531 GstCaps *
532 gst_encoding_profile_get_format (GstEncodingProfile * profile)
533 {
534   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
535
536   return (profile->format ? gst_caps_ref (profile->format) : NULL);
537 }
538
539 /**
540  * gst_encoding_profile_get_preset:
541  * @profile: a #GstEncodingProfile
542  *
543  * Returns: the name of the #GstPreset to be used in the profile.
544  * This is the name that has been set when saving the preset.
545  */
546 const gchar *
547 gst_encoding_profile_get_preset (GstEncodingProfile * profile)
548 {
549   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
550
551   return profile->preset;
552 }
553
554 /**
555  * gst_encoding_profile_get_preset_name:
556  * @profile: a #GstEncodingProfile
557  *
558  * Returns: the name of the #GstPreset factory to be used in the profile.
559  */
560 const gchar *
561 gst_encoding_profile_get_preset_name (GstEncodingProfile * profile)
562 {
563   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
564
565   return profile->preset_name;
566 }
567
568 /**
569  * gst_encoding_profile_get_presence:
570  * @profile: a #GstEncodingProfile
571  *
572  * Returns: The number of times the profile is used in its parent
573  * container profile. If 0, it is not a mandatory stream.
574  */
575 guint
576 gst_encoding_profile_get_presence (GstEncodingProfile * profile)
577 {
578   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), 0);
579
580   return profile->presence;
581 }
582
583 /**
584  * gst_encoding_profile_get_enabled:
585  * @profile: a #GstEncodingProfile
586  *
587  * Returns: Whether @profile is enabled or not
588  *
589  * Since: 1.6
590  */
591 gboolean
592 gst_encoding_profile_is_enabled (GstEncodingProfile * profile)
593 {
594   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
595
596   return profile->enabled;
597 }
598
599 /**
600  * gst_encoding_profile_get_restriction:
601  * @profile: a #GstEncodingProfile
602  *
603  * Returns: (transfer full): The restriction #GstCaps to apply before the encoder
604  * that will be used in the profile. The fields present in restriction caps are
605  * properties of the raw stream (that is before encoding), such as height and
606  * width for video and depth and sampling rate for audio. Does not apply to
607  * #GstEncodingContainerProfile (since there is no corresponding raw stream).
608  * Can be %NULL. Unref after usage.
609  */
610 GstCaps *
611 gst_encoding_profile_get_restriction (GstEncodingProfile * profile)
612 {
613   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
614
615
616   return (profile->restriction ? gst_caps_ref (profile->restriction) : NULL);
617 }
618
619 /**
620  * gst_encoding_profile_set_name:
621  * @profile: a #GstEncodingProfile
622  * @name: (allow-none): the name to set on the profile
623  *
624  * Set @name as the given name for the @profile. A copy of @name will be made
625  * internally.
626  */
627 void
628 gst_encoding_profile_set_name (GstEncodingProfile * profile, const gchar * name)
629 {
630   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
631
632   g_free (profile->name);
633   profile->name = g_strdup (name);
634 }
635
636 /**
637  * gst_encoding_profile_set_description:
638  * @profile: a #GstEncodingProfile
639  * @description: (allow-none): the description to set on the profile
640  *
641  * Set @description as the given description for the @profile. A copy of
642  * @description will be made internally.
643  */
644 void
645 gst_encoding_profile_set_description (GstEncodingProfile * profile,
646     const gchar * description)
647 {
648   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
649
650   g_free (profile->description);
651   profile->description = g_strdup (description);
652 }
653
654 /**
655  * gst_encoding_profile_set_format:
656  * @profile: a #GstEncodingProfile
657  * @format: (transfer none): the media format to use in the profile.
658  *
659  * Sets the media format used in the profile.
660  */
661 void
662 gst_encoding_profile_set_format (GstEncodingProfile * profile, GstCaps * format)
663 {
664   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
665
666   if (profile->format)
667     gst_caps_unref (profile->format);
668   profile->format = gst_caps_ref (format);
669 }
670
671 /**
672  * gst_encoding_profile_get_allow_dynamic_output:
673  * @profile: a #GstEncodingProfile
674  *
675  * Get whether the format that has been negotiated in at some point can be renegotiated
676  * later during the encoding.
677  */
678 gboolean
679 gst_encoding_profile_get_allow_dynamic_output (GstEncodingProfile * profile)
680 {
681   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
682
683   return profile->allow_dynamic_output;
684 }
685
686 /**
687  * gst_encoding_profile_set_allow_dynamic_output:
688  * @profile: a #GstEncodingProfile
689  * @allow_dynamic_output: Whether the format that has been negotiated first can be renegotiated
690  * during the encoding
691  *
692  * Sets whether the format that has been negotiated in at some point can be renegotiated
693  * later during the encoding.
694  */
695 void
696 gst_encoding_profile_set_allow_dynamic_output (GstEncodingProfile * profile,
697     gboolean allow_dynamic_output)
698 {
699   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
700
701   profile->allow_dynamic_output = allow_dynamic_output;
702 }
703
704 /**
705  * gst_encoding_profile_get_single_segment:
706  * @profile: a #GstEncodingProfile
707  *
708  * Returns: #TRUE if the stream represented by @profile should use a single
709  * segment before the encoder, #FALSE otherwise. This means that buffers will be retimestamped
710  * and segments will be eat so as to appear as one segment.
711  *
712  * Since: 1.18
713  */
714 gboolean
715 gst_encoding_profile_get_single_segment (GstEncodingProfile * profile)
716 {
717   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
718
719   return profile->single_segment;
720 }
721
722 /**
723  * gst_encoding_profile_set_single_segment:
724  * @profile: a #GstEncodingProfile
725  * @single_segment: #TRUE if the stream represented by @profile should use a
726  * single segment before the encoder, #FALSE otherwise.
727  *
728  * If using a single segment, buffers will be retimestamped and segments will be
729  * eat so as to appear as one segment.
730  *
731  * > *NOTE*: Single segment is not property supported when using
732  * > #encodebin:avoid-reencoding
733  *
734  * Since: 1.18
735  */
736 void
737 gst_encoding_profile_set_single_segment (GstEncodingProfile * profile,
738     gboolean single_segment)
739 {
740   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
741
742   profile->single_segment = single_segment;
743 }
744
745 /**
746  * gst_encoding_profile_set_preset:
747  * @profile: a #GstEncodingProfile
748  * @preset: (nullable): the element preset to use
749  *
750  * Sets the name of the #GstElement that implements the #GstPreset interface
751  * to use for the profile.
752  * This is the name that has been set when saving the preset.
753  */
754 void
755 gst_encoding_profile_set_preset (GstEncodingProfile * profile,
756     const gchar * preset)
757 {
758   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
759
760   g_free (profile->preset);
761   profile->preset = g_strdup (preset);
762 }
763
764 /**
765  * gst_encoding_profile_set_preset_name:
766  * @profile: a #GstEncodingProfile
767  * @preset_name: (allow-none): The name of the preset to use in this @profile.
768  *
769  * Sets the name of the #GstPreset's factory to be used in the profile.
770  */
771 void
772 gst_encoding_profile_set_preset_name (GstEncodingProfile * profile,
773     const gchar * preset_name)
774 {
775   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
776
777   g_free (profile->preset_name);
778   profile->preset_name = g_strdup (preset_name);
779 }
780
781 /**
782  * gst_encoding_profile_set_presence:
783  * @profile: a #GstEncodingProfile
784  * @presence: the number of time the profile can be used
785  *
786  * Set the number of time the profile is used in its parent
787  * container profile. If 0, it is not a mandatory stream
788  */
789 void
790 gst_encoding_profile_set_presence (GstEncodingProfile * profile, guint presence)
791 {
792   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
793
794   profile->presence = presence;
795 }
796
797 /**
798  * gst_encoding_profile_set_enabled:
799  * @profile: a #GstEncodingProfile
800  * @enabled: %FALSE to disable @profile, %TRUE to enable it
801  *
802  * Set whether the profile should be used or not.
803  *
804  * Since: 1.6
805  */
806 void
807 gst_encoding_profile_set_enabled (GstEncodingProfile * profile,
808     gboolean enabled)
809 {
810   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
811
812   profile->enabled = enabled;
813 }
814
815 /**
816  * gst_encoding_profile_set_restriction:
817  * @profile: a #GstEncodingProfile
818  * @restriction: (allow-none) (transfer full): the restriction to apply
819  *
820  * Set the restriction #GstCaps to apply before the encoder
821  * that will be used in the profile. See gst_encoding_profile_get_restriction()
822  * for more about restrictions. Does not apply to #GstEncodingContainerProfile.
823  */
824 void
825 gst_encoding_profile_set_restriction (GstEncodingProfile * profile,
826     GstCaps * restriction)
827 {
828   g_return_if_fail (restriction == NULL || GST_IS_CAPS (restriction));
829   g_return_if_fail (GST_IS_ENCODING_PROFILE (profile));
830
831   if (profile->restriction)
832     gst_caps_unref (profile->restriction);
833   profile->restriction = restriction;
834
835   g_object_notify_by_pspec (G_OBJECT (profile),
836       _properties[PROP_RESTRICTION_CAPS]);
837 }
838
839 /**
840  * gst_encoding_profile_set_element_properties:
841  * @self: a #GstEncodingProfile
842  * @element_properties: (transfer full): A #GstStructure defining the properties
843  * to be set to the element the profile represents.
844  *
845  * This allows setting the muxing/encoding element properties.
846  *
847  * **Set properties generically**
848  *
849  * ``` properties
850  *  [element-properties, boolean-prop=true, string-prop="hi"]
851  * ```
852  *
853  * **Mapping properties with well known element factories**
854  *
855  * ``` properties
856  * element-properties-map, map = {
857  *      [openh264enc, gop-size=32, ],
858  *      [x264enc, key-int-max=32, tune=zerolatency],
859  *  }
860  * ```
861  *
862  * Since: 1.20
863  */
864 void
865 gst_encoding_profile_set_element_properties (GstEncodingProfile * self,
866     GstStructure * element_properties)
867 {
868   g_return_if_fail (GST_IS_ENCODING_PROFILE (self));
869   g_return_if_fail (!element_properties
870       || GST_IS_STRUCTURE (element_properties));
871
872 #ifndef G_DISABLE_CHECKS
873   if (element_properties &&
874       (gst_structure_has_name (element_properties, "element-properties-map")
875           || gst_structure_has_name (element_properties, "properties-map")
876           || gst_structure_has_name (element_properties, "map")))
877     g_return_if_fail (gst_structure_has_field_typed (element_properties, "map",
878             GST_TYPE_LIST));
879 #endif
880
881   PROFILE_LOCK (self);
882   if (self->element_properties)
883     gst_structure_free (self->element_properties);
884   if (element_properties)
885     self->element_properties = element_properties;
886   else
887     self->element_properties = NULL;
888   PROFILE_UNLOCK (self);
889
890   g_object_notify_by_pspec (G_OBJECT (self),
891       _properties[PROP_ELEMENT_PROPERTIES]);
892 }
893
894 /**
895  * gst_encoding_profile_get_element_properties:
896  * @self: a #GstEncodingProfile
897  *
898  * Returns: (transfer full) (nullable): The properties that are going to be set on the underlying element
899  *
900  * Since: 1.20
901  */
902 GstStructure *
903 gst_encoding_profile_get_element_properties (GstEncodingProfile * self)
904 {
905   GstStructure *res = NULL;
906
907   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (self), NULL);
908
909   PROFILE_LOCK (self);
910   if (self->element_properties)
911     res = gst_structure_copy (self->element_properties);
912   PROFILE_UNLOCK (self);
913
914   return res;
915 }
916
917 /* Container profiles */
918
919 struct _GstEncodingContainerProfile
920 {
921   GstEncodingProfile parent;
922
923   GList *encodingprofiles;
924 };
925
926 struct _GstEncodingContainerProfileClass
927 {
928   GstEncodingProfileClass parent;
929 };
930
931 G_DEFINE_TYPE (GstEncodingContainerProfile, gst_encoding_container_profile,
932     GST_TYPE_ENCODING_PROFILE);
933
934 static void
935 gst_encoding_container_profile_init (GstEncodingContainerProfile * prof)
936 {
937   /* Nothing to initialize */
938 }
939
940 static void
941 gst_encoding_container_profile_finalize (GObject * object)
942 {
943   GstEncodingContainerProfile *prof = (GstEncodingContainerProfile *) object;
944
945   g_list_foreach (prof->encodingprofiles, (GFunc) g_object_unref, NULL);
946   g_list_free (prof->encodingprofiles);
947
948   G_OBJECT_CLASS (gst_encoding_container_profile_parent_class)->finalize
949       ((GObject *) prof);
950 }
951
952 static void
953 gst_encoding_container_profile_copy (GstEncodingProfile * profile,
954     GstEncodingProfile * copy_profile)
955 {
956   GstEncodingContainerProfile *self = GST_ENCODING_CONTAINER_PROFILE (profile),
957       *copy = GST_ENCODING_CONTAINER_PROFILE (copy_profile);
958   GList *tmp;
959
960   for (tmp = self->encodingprofiles; tmp; tmp = tmp->next) {
961     gst_encoding_container_profile_add_profile (copy,
962         gst_encoding_profile_copy (tmp->data));
963   }
964 }
965
966 static void
967 gst_encoding_container_profile_class_init (GstEncodingContainerProfileClass * k)
968 {
969   GObjectClass *gobject_class = (GObjectClass *) k;
970
971   gobject_class->finalize = gst_encoding_container_profile_finalize;
972
973   ((GstEncodingProfileClass *) k)->copy = gst_encoding_container_profile_copy;
974 }
975
976 /**
977  * gst_encoding_container_profile_get_profiles:
978  * @profile: a #GstEncodingContainerProfile
979  *
980  * Returns: (element-type GstPbutils.EncodingProfile) (transfer none):
981  * the list of contained #GstEncodingProfile.
982  */
983 const GList *
984 gst_encoding_container_profile_get_profiles (GstEncodingContainerProfile *
985     profile)
986 {
987   g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (profile), NULL);
988
989   return profile->encodingprofiles;
990 }
991
992 /* Video profiles */
993
994 struct _GstEncodingVideoProfile
995 {
996   GstEncodingProfile parent;
997
998   guint pass;
999   gboolean variableframerate;
1000 };
1001
1002 struct _GstEncodingVideoProfileClass
1003 {
1004   GstEncodingProfileClass parent;
1005 };
1006
1007 G_DEFINE_TYPE (GstEncodingVideoProfile, gst_encoding_video_profile,
1008     GST_TYPE_ENCODING_PROFILE);
1009
1010 static void
1011 gst_encoding_video_profile_copy (GstEncodingProfile * profile,
1012     GstEncodingProfile * copy_profile)
1013 {
1014   GstEncodingVideoProfile *self = GST_ENCODING_VIDEO_PROFILE (profile),
1015       *copy = GST_ENCODING_VIDEO_PROFILE (copy_profile);
1016
1017   copy->pass = self->pass;
1018   copy->variableframerate = self->variableframerate;
1019 }
1020
1021 static void
1022 gst_encoding_video_profile_init (GstEncodingVideoProfile * prof)
1023 {
1024   /* Nothing to initialize */
1025 }
1026
1027 static void
1028 gst_encoding_video_profile_class_init (GstEncodingVideoProfileClass * klass)
1029 {
1030   ((GstEncodingProfileClass *) klass)->copy = gst_encoding_video_profile_copy;
1031 }
1032
1033 /**
1034  * gst_encoding_video_profile_get_pass:
1035  * @prof: a #GstEncodingVideoProfile
1036  *
1037  * Get the pass number if this is part of a multi-pass profile.
1038  *
1039  * Returns: The pass number. Starts at 1 for multi-pass. 0 if this is
1040  * not a multi-pass profile
1041  */
1042 guint
1043 gst_encoding_video_profile_get_pass (GstEncodingVideoProfile * prof)
1044 {
1045   g_return_val_if_fail (GST_IS_ENCODING_VIDEO_PROFILE (prof), 0);
1046
1047   return prof->pass;
1048 }
1049
1050 /**
1051  * gst_encoding_video_profile_get_variableframerate:
1052  * @prof: a #GstEncodingVideoProfile
1053  *
1054  * > *NOTE*: Fixed framerate won't be enforced when #encodebin:avoid-reencoding
1055  * > is set.
1056  *
1057  * Returns: Whether non-constant video framerate is allowed for encoding.
1058  */
1059 gboolean
1060 gst_encoding_video_profile_get_variableframerate (GstEncodingVideoProfile *
1061     prof)
1062 {
1063   g_return_val_if_fail (GST_IS_ENCODING_VIDEO_PROFILE (prof), FALSE);
1064
1065   return prof->variableframerate;
1066 }
1067
1068 /**
1069  * gst_encoding_video_profile_set_pass:
1070  * @prof: a #GstEncodingVideoProfile
1071  * @pass: the pass number for this profile
1072  *
1073  * Sets the pass number of this video profile. The first pass profile should have
1074  * this value set to 1. If this video profile isn't part of a multi-pass profile,
1075  * you may set it to 0 (the default value).
1076  */
1077 void
1078 gst_encoding_video_profile_set_pass (GstEncodingVideoProfile * prof, guint pass)
1079 {
1080   g_return_if_fail (GST_IS_ENCODING_VIDEO_PROFILE (prof));
1081
1082   prof->pass = pass;
1083 }
1084
1085 /**
1086  * gst_encoding_video_profile_set_variableframerate:
1087  * @prof: a #GstEncodingVideoProfile
1088  * @variableframerate: a boolean
1089  *
1090  * If set to %TRUE, then the incoming stream will be allowed to have non-constant
1091  * framerate. If set to %FALSE (default value), then the incoming stream will
1092  * be normalized by dropping/duplicating frames in order to produce a
1093  * constance framerate.
1094  */
1095 void
1096 gst_encoding_video_profile_set_variableframerate (GstEncodingVideoProfile *
1097     prof, gboolean variableframerate)
1098 {
1099   g_return_if_fail (GST_IS_ENCODING_VIDEO_PROFILE (prof));
1100
1101   prof->variableframerate = variableframerate;
1102 }
1103
1104 /* Audio profiles */
1105
1106 struct _GstEncodingAudioProfile
1107 {
1108   GstEncodingProfile parent;
1109 };
1110
1111 struct _GstEncodingAudioProfileClass
1112 {
1113   GstEncodingProfileClass parent;
1114 };
1115
1116 G_DEFINE_TYPE (GstEncodingAudioProfile, gst_encoding_audio_profile,
1117     GST_TYPE_ENCODING_PROFILE);
1118
1119 static void
1120 gst_encoding_audio_profile_init (GstEncodingAudioProfile * prof)
1121 {
1122   /* Nothing to initialize */
1123 }
1124
1125 static void
1126 gst_encoding_audio_profile_class_init (GstEncodingAudioProfileClass * klass)
1127 {
1128 }
1129
1130 static inline gboolean
1131 _gst_caps_is_equal_safe (GstCaps * a, GstCaps * b)
1132 {
1133   if (a == b)
1134     return TRUE;
1135   if ((a == NULL) || (b == NULL))
1136     return FALSE;
1137   return gst_caps_is_equal (a, b);
1138 }
1139
1140 static gint
1141 _compare_container_encoding_profiles (GstEncodingContainerProfile * ca,
1142     GstEncodingContainerProfile * cb)
1143 {
1144   GList *tmp;
1145
1146   if (g_list_length (ca->encodingprofiles) !=
1147       g_list_length (cb->encodingprofiles))
1148     return -1;
1149
1150   for (tmp = ca->encodingprofiles; tmp; tmp = tmp->next) {
1151     GstEncodingProfile *prof = (GstEncodingProfile *) tmp->data;
1152     if (!gst_encoding_container_profile_contains_profile (ca, prof))
1153       return -1;
1154   }
1155
1156   return 0;
1157 }
1158
1159 static gint
1160 _compare_encoding_profiles (const GstEncodingProfile * a,
1161     const GstEncodingProfile * b)
1162 {
1163   if ((G_TYPE_FROM_INSTANCE (a) != G_TYPE_FROM_INSTANCE (b)) ||
1164       !_gst_caps_is_equal_safe (a->format, b->format) ||
1165       (g_strcmp0 (a->preset, b->preset) != 0) ||
1166       (g_strcmp0 (a->preset_name, b->preset_name) != 0) ||
1167       (g_strcmp0 (a->name, b->name) != 0) ||
1168       (g_strcmp0 (a->description, b->description) != 0))
1169     return -1;
1170
1171   if (GST_IS_ENCODING_CONTAINER_PROFILE (a))
1172     return
1173         _compare_container_encoding_profiles (GST_ENCODING_CONTAINER_PROFILE
1174         (a), GST_ENCODING_CONTAINER_PROFILE (b));
1175
1176   if (GST_IS_ENCODING_VIDEO_PROFILE (a)) {
1177     GstEncodingVideoProfile *va = (GstEncodingVideoProfile *) a;
1178     GstEncodingVideoProfile *vb = (GstEncodingVideoProfile *) b;
1179
1180     if ((va->pass != vb->pass)
1181         || (va->variableframerate != vb->variableframerate))
1182       return -1;
1183   }
1184
1185   return 0;
1186 }
1187
1188 /**
1189  * gst_encoding_container_profile_contains_profile:
1190  * @container: a #GstEncodingContainerProfile
1191  * @profile: a #GstEncodingProfile
1192  *
1193  * Checks if @container contains a #GstEncodingProfile identical to
1194  * @profile.
1195  *
1196  * Returns: %TRUE if @container contains a #GstEncodingProfile identical
1197  * to @profile, else %FALSE.
1198  */
1199 gboolean
1200 gst_encoding_container_profile_contains_profile (GstEncodingContainerProfile *
1201     container, GstEncodingProfile * profile)
1202 {
1203   g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE);
1204   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
1205
1206   return (g_list_find_custom (container->encodingprofiles, profile,
1207           (GCompareFunc) _compare_encoding_profiles) != NULL);
1208 }
1209
1210 /**
1211  * gst_encoding_container_profile_add_profile:
1212  * @container: the #GstEncodingContainerProfile to use
1213  * @profile: (transfer full): the #GstEncodingProfile to add.
1214  *
1215  * Add a #GstEncodingProfile to the list of profiles handled by @container.
1216  *
1217  * No copy of @profile will be made, if you wish to use it elsewhere after this
1218  * method you should increment its reference count.
1219  *
1220  * Returns: %TRUE if the @stream was properly added, else %FALSE.
1221  */
1222 gboolean
1223 gst_encoding_container_profile_add_profile (GstEncodingContainerProfile *
1224     container, GstEncodingProfile * profile)
1225 {
1226   g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (container), FALSE);
1227   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
1228
1229   container->encodingprofiles =
1230       g_list_append (container->encodingprofiles, profile);
1231
1232   return TRUE;
1233 }
1234
1235 static GstEncodingProfile *
1236 common_creation (GType objtype, GstCaps * format, const gchar * preset,
1237     const gchar * name, const gchar * description, GstCaps * restriction,
1238     guint presence)
1239 {
1240   GstEncodingProfile *prof;
1241
1242   prof = (GstEncodingProfile *) g_object_new (objtype, NULL);
1243
1244   if (name)
1245     prof->name = g_strdup (name);
1246   if (description)
1247     prof->description = g_strdup (description);
1248   if (preset)
1249     prof->preset = g_strdup (preset);
1250   if (format)
1251     prof->format = gst_caps_ref (format);
1252   if (restriction)
1253     prof->restriction = gst_caps_ref (restriction);
1254   prof->presence = presence;
1255   prof->preset_name = NULL;
1256   prof->allow_dynamic_output = TRUE;
1257   prof->enabled = TRUE;
1258
1259   return prof;
1260 }
1261
1262 /**
1263  * gst_encoding_container_profile_new:
1264  * @name: (allow-none): The name of the container profile, can be %NULL
1265  * @description: (allow-none): The description of the container profile,
1266  *     can be %NULL
1267  * @format: (transfer none): The format to use for this profile
1268  * @preset: (allow-none): The preset to use for this profile.
1269  *
1270  * Creates a new #GstEncodingContainerProfile.
1271  *
1272  * Returns: The newly created #GstEncodingContainerProfile.
1273  */
1274 GstEncodingContainerProfile *
1275 gst_encoding_container_profile_new (const gchar * name,
1276     const gchar * description, GstCaps * format, const gchar * preset)
1277 {
1278   g_return_val_if_fail (GST_IS_CAPS (format), NULL);
1279
1280   return (GstEncodingContainerProfile *)
1281       common_creation (GST_TYPE_ENCODING_CONTAINER_PROFILE, format, preset,
1282       name, description, NULL, 0);
1283 }
1284
1285 /**
1286  * gst_encoding_video_profile_new:
1287  * @format: (transfer none): the #GstCaps
1288  * @preset: (allow-none): the preset(s) to use on the encoder, can be %NULL
1289  * @restriction: (allow-none): the #GstCaps used to restrict the input to the encoder, can be
1290  * NULL. See gst_encoding_profile_get_restriction() for more details.
1291  * @presence: the number of time this stream must be used. 0 means any number of
1292  *  times (including never)
1293  *
1294  * Creates a new #GstEncodingVideoProfile
1295  *
1296  * All provided allocatable arguments will be internally copied, so can be
1297  * safely freed/unreferenced after calling this method.
1298  *
1299  * If you wish to control the pass number (in case of multi-pass scenarios),
1300  * please refer to the gst_encoding_video_profile_set_pass() documentation.
1301  *
1302  * If you wish to use/force a constant framerate please refer to the
1303  * gst_encoding_video_profile_set_variableframerate() documentation.
1304  *
1305  * Returns: the newly created #GstEncodingVideoProfile.
1306  */
1307 GstEncodingVideoProfile *
1308 gst_encoding_video_profile_new (GstCaps * format, const gchar * preset,
1309     GstCaps * restriction, guint presence)
1310 {
1311   return (GstEncodingVideoProfile *)
1312       common_creation (GST_TYPE_ENCODING_VIDEO_PROFILE, format, preset, NULL,
1313       NULL, restriction, presence);
1314 }
1315
1316 /**
1317  * gst_encoding_audio_profile_new:
1318  * @format: (transfer none): the #GstCaps
1319  * @preset: (allow-none): the preset(s) to use on the encoder, can be %NULL
1320  * @restriction: (allow-none): the #GstCaps used to restrict the input to the encoder, can be
1321  * NULL. See gst_encoding_profile_get_restriction() for more details.
1322  * @presence: the number of time this stream must be used. 0 means any number of
1323  *  times (including never)
1324  *
1325  * Creates a new #GstEncodingAudioProfile
1326  *
1327  * All provided allocatable arguments will be internally copied, so can be
1328  * safely freed/unreferenced after calling this method.
1329  *
1330  * Returns: the newly created #GstEncodingAudioProfile.
1331  */
1332 GstEncodingAudioProfile *
1333 gst_encoding_audio_profile_new (GstCaps * format, const gchar * preset,
1334     GstCaps * restriction, guint presence)
1335 {
1336   return (GstEncodingAudioProfile *)
1337       common_creation (GST_TYPE_ENCODING_AUDIO_PROFILE, format, preset, NULL,
1338       NULL, restriction, presence);
1339 }
1340
1341
1342 /**
1343  * gst_encoding_profile_is_equal:
1344  * @a: a #GstEncodingProfile
1345  * @b: a #GstEncodingProfile
1346  *
1347  * Checks whether the two #GstEncodingProfile are equal
1348  *
1349  * Returns: %TRUE if @a and @b are equal, else %FALSE.
1350  */
1351 gboolean
1352 gst_encoding_profile_is_equal (GstEncodingProfile * a, GstEncodingProfile * b)
1353 {
1354   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (a), FALSE);
1355   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (b), FALSE);
1356
1357   return (_compare_encoding_profiles (a, b) == 0);
1358 }
1359
1360
1361 /**
1362  * gst_encoding_profile_get_input_caps:
1363  * @profile: a #GstEncodingProfile
1364  *
1365  * Computes the full output caps that this @profile will be able to consume.
1366  *
1367  * Returns: (transfer full): The full caps the given @profile can consume. Call
1368  * gst_caps_unref() when you are done with the caps.
1369  */
1370 GstCaps *
1371 gst_encoding_profile_get_input_caps (GstEncodingProfile * profile)
1372 {
1373   GstCaps *out, *tmp;
1374   GList *ltmp;
1375   GstStructure *st, *outst;
1376   GQuark out_name;
1377   guint i, len;
1378   GstCaps *fcaps;
1379
1380   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
1381
1382   if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
1383     GstCaps *res = gst_caps_new_empty ();
1384
1385     for (ltmp = GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles;
1386         ltmp; ltmp = ltmp->next) {
1387       GstEncodingProfile *sprof = (GstEncodingProfile *) ltmp->data;
1388       res = gst_caps_merge (res, gst_encoding_profile_get_input_caps (sprof));
1389     }
1390     return res;
1391   }
1392
1393   fcaps = profile->format;
1394
1395   /* fast-path */
1396   if ((profile->restriction == NULL) || gst_caps_is_any (profile->restriction))
1397     return gst_caps_ref (fcaps);
1398
1399   /* Combine the format with the restriction caps */
1400   outst = gst_caps_get_structure (fcaps, 0);
1401   out_name = gst_structure_get_name_id (outst);
1402   tmp = gst_caps_new_empty ();
1403   len = gst_caps_get_size (profile->restriction);
1404
1405   for (i = 0; i < len; i++) {
1406     st = gst_structure_copy (gst_caps_get_structure (profile->restriction, i));
1407     st->name = out_name;
1408     gst_caps_append_structure (tmp, st);
1409   }
1410
1411   out = gst_caps_intersect (tmp, fcaps);
1412   gst_caps_unref (tmp);
1413
1414   return out;
1415 }
1416
1417 /**
1418  * gst_encoding_profile_get_type_nick:
1419  * @profile: a #GstEncodingProfile
1420  *
1421  * Returns: the human-readable name of the type of @profile.
1422  */
1423 const gchar *
1424 gst_encoding_profile_get_type_nick (GstEncodingProfile * profile)
1425 {
1426   if (GST_IS_ENCODING_CONTAINER_PROFILE (profile))
1427     return "container";
1428   if (GST_IS_ENCODING_VIDEO_PROFILE (profile))
1429     return "video";
1430   if (GST_IS_ENCODING_AUDIO_PROFILE (profile))
1431     return "audio";
1432   return NULL;
1433 }
1434
1435 extern const gchar *pb_utils_get_file_extension_from_caps (const GstCaps *
1436     caps);
1437 gboolean pb_utils_is_tag (const GstCaps * caps);
1438
1439 static gboolean
1440 gst_encoding_profile_has_format (GstEncodingProfile * profile,
1441     const gchar * media_type)
1442 {
1443   GstCaps *caps;
1444   gboolean ret;
1445
1446   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
1447
1448   caps = gst_encoding_profile_get_format (profile);
1449   ret = gst_structure_has_name (gst_caps_get_structure (caps, 0), media_type);
1450   gst_caps_unref (caps);
1451
1452   return ret;
1453 }
1454
1455 static gboolean
1456 gst_encoding_container_profile_has_video (GstEncodingContainerProfile * profile)
1457 {
1458   const GList *l;
1459
1460   g_return_val_if_fail (GST_IS_ENCODING_CONTAINER_PROFILE (profile), FALSE);
1461
1462   for (l = profile->encodingprofiles; l != NULL; l = l->next) {
1463     if (GST_IS_ENCODING_VIDEO_PROFILE (l->data))
1464       return TRUE;
1465     if (GST_IS_ENCODING_CONTAINER_PROFILE (l->data) &&
1466         gst_encoding_container_profile_has_video (l->data))
1467       return TRUE;
1468   }
1469
1470   return FALSE;
1471 }
1472
1473 /**
1474  * gst_encoding_profile_get_file_extension:
1475  * @profile: a #GstEncodingProfile
1476  *
1477  * Returns: a suitable file extension for @profile, or NULL.
1478  */
1479 const gchar *
1480 gst_encoding_profile_get_file_extension (GstEncodingProfile * profile)
1481 {
1482   GstEncodingContainerProfile *cprofile;
1483   const gchar *ext = NULL;
1484   gboolean has_video;
1485   GstCaps *caps;
1486   guint num_children;
1487
1488   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), NULL);
1489
1490   caps = gst_encoding_profile_get_format (profile);
1491   ext = pb_utils_get_file_extension_from_caps (caps);
1492
1493   if (!GST_IS_ENCODING_CONTAINER_PROFILE (profile))
1494     goto done;
1495
1496   cprofile = GST_ENCODING_CONTAINER_PROFILE (profile);
1497
1498   num_children = g_list_length (cprofile->encodingprofiles);
1499
1500   /* if it's a tag container profile (e.g. id3mux/apemux), we need
1501    * to look at what's inside it */
1502   if (pb_utils_is_tag (caps)) {
1503     GST_DEBUG ("tag container profile");
1504     if (num_children == 1) {
1505       GstEncodingProfile *child_profile = cprofile->encodingprofiles->data;
1506
1507       ext = gst_encoding_profile_get_file_extension (child_profile);
1508     } else {
1509       GST_WARNING ("expected exactly one child profile with tag profile");
1510     }
1511     goto done;
1512   }
1513
1514   if (num_children == 0)
1515     goto done;
1516
1517   /* special cases */
1518   has_video = gst_encoding_container_profile_has_video (cprofile);
1519
1520   /* Ogg */
1521   if (g_strcmp0 (ext, "ogg") == 0) {
1522     /* ogg with video => .ogv */
1523     if (has_video) {
1524       ext = "ogv";
1525       goto done;
1526     }
1527     /* ogg with just speex audio => .spx */
1528     if (num_children == 1) {
1529       GstEncodingProfile *child_profile = cprofile->encodingprofiles->data;
1530
1531       if (GST_IS_ENCODING_AUDIO_PROFILE (child_profile) &&
1532           gst_encoding_profile_has_format (child_profile, "audio/x-speex")) {
1533         ext = "spx";
1534         goto done;
1535       }
1536     }
1537     /* does anyone actually use .oga for ogg audio files? */
1538     goto done;
1539   }
1540
1541   /* Matroska */
1542   if (has_video && g_strcmp0 (ext, "mka") == 0) {
1543     ext = "mkv";
1544     goto done;
1545   }
1546
1547   /* Windows Media / ASF */
1548   if (gst_encoding_profile_has_format (profile, "video/x-ms-asf")) {
1549     const GList *l;
1550     guint num_wmv = 0, num_wma = 0, num_other = 0;
1551
1552     for (l = cprofile->encodingprofiles; l != NULL; l = l->next) {
1553       if (gst_encoding_profile_has_format (l->data, "video/x-wmv"))
1554         ++num_wmv;
1555       else if (gst_encoding_profile_has_format (l->data, "audio/x-wma"))
1556         ++num_wma;
1557       else
1558         ++num_other;
1559     }
1560
1561     if (num_other > 0)
1562       ext = "asf";
1563     else if (num_wmv > 0)
1564       ext = "wmv";
1565     else if (num_wma > 0)
1566       ext = "wma";
1567
1568     goto done;
1569   }
1570
1571 done:
1572
1573   GST_INFO ("caps %" GST_PTR_FORMAT ", ext: %s", caps, GST_STR_NULL (ext));
1574   gst_caps_unref (caps);
1575   return ext;
1576 }
1577
1578 /**
1579  * gst_encoding_profile_find:
1580  * @targetname: (transfer none): The name of the target
1581  * @profilename: (transfer none) (allow-none): The name of the profile, if %NULL
1582  * provided, it will default to the encoding profile called `default`.
1583  * @category: (transfer none) (allow-none): The target category. Can be %NULL
1584  *
1585  * Find the #GstEncodingProfile with the specified name and category.
1586  *
1587  * Returns: (transfer full): The matching #GstEncodingProfile or %NULL.
1588  */
1589 GstEncodingProfile *
1590 gst_encoding_profile_find (const gchar * targetname, const gchar * profilename,
1591     const gchar * category)
1592 {
1593   GstEncodingProfile *res = NULL;
1594   GstEncodingTarget *target;
1595
1596   g_return_val_if_fail (targetname != NULL, NULL);
1597
1598   target = gst_encoding_target_load (targetname, category, NULL);
1599   if (target) {
1600     res =
1601         gst_encoding_target_get_profile (target,
1602         profilename ? profilename : "default");
1603     gst_encoding_target_unref (target);
1604   }
1605
1606   return res;
1607 }
1608
1609 static GstEncodingProfile *
1610 combo_search (const gchar * pname)
1611 {
1612   GstEncodingProfile *res = NULL;
1613   gchar **split;
1614   gint split_length;
1615
1616   /* Splitup */
1617   split = g_strsplit (pname, "/", 3);
1618   split_length = g_strv_length (split);
1619   if (split_length > 3)
1620     goto done;
1621
1622   res = gst_encoding_profile_find (split[0],
1623       split_length == 2 ? split[1] : NULL, split_length == 3 ? split[2] : NULL);
1624
1625
1626 done:
1627   g_strfreev (split);
1628
1629   return res;
1630 }
1631
1632 static GstCaps *
1633 get_profile_format_from_possible_factory_name (const gchar * factory_desc,
1634     gchar ** new_factory_name, GstCaps ** restrictions,
1635     gboolean * is_rendering_muxer)
1636 {
1637   GList *tmp;
1638   GstCaps *caps = NULL, *tmpcaps = gst_caps_from_string (factory_desc);
1639   GstStructure *tmpstruct;
1640   GstElementFactory *fact = NULL;
1641
1642   if (is_rendering_muxer)
1643     *is_rendering_muxer = FALSE;
1644   *new_factory_name = NULL;
1645   if (gst_caps_get_size (tmpcaps) != 1)
1646     goto done;
1647
1648   tmpstruct = gst_caps_get_structure (tmpcaps, 0);
1649   fact = gst_element_factory_find (gst_structure_get_name (tmpstruct));
1650   if (!fact)
1651     goto done;
1652
1653   if (!gst_element_factory_list_is_type (fact,
1654           GST_ELEMENT_FACTORY_TYPE_ENCODER | GST_ELEMENT_FACTORY_TYPE_MUXER)) {
1655     GST_ERROR_OBJECT (fact,
1656         "is not an encoder or muxer, it can't be"
1657         " used in an encoding profile.");
1658     goto done;
1659   }
1660
1661   for (tmp = (GList *) gst_element_factory_get_static_pad_templates (fact);
1662       tmp; tmp = tmp->next) {
1663     GstStaticPadTemplate *templ = ((GstStaticPadTemplate *) tmp->data);
1664
1665     if (templ->direction == GST_PAD_SRC) {
1666       GstCaps *tmpcaps = gst_static_caps_get (&templ->static_caps);
1667
1668       if (gst_caps_get_size (tmpcaps) > 0)
1669         caps =
1670             gst_caps_new_empty_simple (gst_structure_get_name
1671             (gst_caps_get_structure (tmpcaps, 0)));
1672
1673       gst_caps_unref (tmpcaps);
1674       if (caps)
1675         break;
1676     }
1677   }
1678
1679   if (caps) {
1680     *new_factory_name = g_strdup (gst_structure_get_name (tmpstruct));
1681
1682     if (gst_structure_n_fields (tmpstruct) && restrictions) {
1683       const gchar *sname =
1684           gst_structure_get_name (gst_caps_get_structure (caps, 0));
1685
1686       if (g_str_has_prefix (sname, "audio/"))
1687         gst_structure_set_name (tmpstruct, "audio/x-raw");
1688       else if (g_str_has_prefix (sname, "video/") ||
1689           g_str_has_prefix (sname, "image/"))
1690         gst_structure_set_name (tmpstruct, "video/x-raw");
1691
1692       *restrictions = tmpcaps;
1693       tmpcaps = NULL;
1694     }
1695   } else if (gst_element_factory_list_is_type (fact,
1696           GST_ELEMENT_FACTORY_TYPE_MUXER)) {
1697     *new_factory_name = g_strdup (gst_structure_get_name (tmpstruct));
1698
1699     caps = gst_caps_ref (gst_caps_new_empty ());
1700     if (is_rendering_muxer)
1701       *is_rendering_muxer = TRUE;
1702   }
1703
1704
1705 done:
1706   if (fact)
1707     gst_object_unref (fact);
1708
1709   if (tmpcaps)
1710     gst_caps_unref (tmpcaps);
1711
1712   return caps;
1713 }
1714
1715 static GstEncodingProfile *
1716 create_encoding_profile_from_caps (GstCaps * caps, gchar * preset_name,
1717     GstCaps * restrictioncaps, gint presence, gboolean single_segment,
1718     gchar * factory_name, GList * muxers_and_encoders, GstCaps * raw_audio_caps,
1719     GstCaps * raw_video_caps, gboolean is_rendering_muxer)
1720 {
1721   GstEncodingProfile *profile = NULL;
1722   GList *factories = NULL;
1723   gboolean is_raw_audio = FALSE, is_raw_video = FALSE;
1724
1725   if (is_rendering_muxer) {
1726     profile =
1727         GST_ENCODING_PROFILE (gst_encoding_container_profile_new
1728         ("User profile", "User profile", caps, NULL));
1729     goto done;
1730   }
1731
1732   if (gst_caps_can_intersect (raw_audio_caps, caps)) {
1733     is_raw_audio = TRUE;
1734   } else if (gst_caps_can_intersect (raw_video_caps, caps)) {
1735     is_raw_video = TRUE;
1736   } else {
1737     factories = gst_element_factory_list_filter (muxers_and_encoders, caps,
1738         GST_PAD_SRC, FALSE);
1739
1740     if (!factories) {
1741       GST_INFO ("Could not find factory for %" GST_PTR_FORMAT, caps);
1742       return NULL;
1743     }
1744   }
1745
1746   if (is_raw_audio || (factories
1747           && gst_element_factory_list_is_type (factories->data,
1748               GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER)))
1749     profile =
1750         GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, preset_name,
1751             restrictioncaps, presence));
1752   else if (is_raw_video || (factories
1753           && gst_element_factory_list_is_type (factories->data,
1754               GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER)))
1755     profile =
1756         GST_ENCODING_PROFILE (gst_encoding_video_profile_new (caps, preset_name,
1757             restrictioncaps, presence));
1758   else if (gst_element_factory_list_is_type (factories->data,
1759           GST_ELEMENT_FACTORY_TYPE_MUXER))
1760     profile =
1761         GST_ENCODING_PROFILE (gst_encoding_container_profile_new
1762         ("User profile", "User profile", caps, NULL));
1763
1764   if (factories)
1765     gst_plugin_feature_list_free (factories);
1766
1767 done:
1768   if (factory_name && profile)
1769     gst_encoding_profile_set_preset_name (profile, factory_name);
1770   gst_encoding_profile_set_single_segment (profile, single_segment);
1771
1772   g_free (factory_name);
1773
1774   return profile;
1775 }
1776
1777 static gboolean
1778 gst_structure_validate_name (const gchar * name)
1779 {
1780   const gchar *s;
1781
1782   g_return_val_if_fail (name != NULL, FALSE);
1783
1784   if (G_UNLIKELY (!g_ascii_isalpha (*name)))
1785     return FALSE;
1786
1787   /* FIXME: test name string more */
1788   s = &name[1];
1789   while (*s && (g_ascii_isalnum (*s) || strchr ("/-_.:+", *s) != NULL))
1790     s++;
1791
1792   if (*s == ',')
1793     return TRUE;
1794
1795   if (G_UNLIKELY (*s != '\0'))
1796     return FALSE;
1797
1798   return TRUE;
1799 }
1800
1801 static GstEncodingProfile *
1802 create_encoding_stream_profile (gchar * serialized_profile,
1803     GList * muxers_and_encoders, GstCaps * raw_audio_caps,
1804     GstCaps * raw_video_caps)
1805 {
1806   GstCaps *caps;
1807   guint presence = 0;
1808   gboolean single_segment = FALSE;
1809   gchar *strcaps, *strpresence, **strprops_v, **restriction_format,
1810       **preset_v, *preset_name = NULL, *factory_name = NULL,
1811       *variable_framerate = NULL;
1812   GstStructure *element_properties = NULL;
1813   GstCaps *restrictioncaps = NULL;
1814   GstEncodingProfile *profile = NULL;
1815
1816   restriction_format = g_strsplit (serialized_profile, "->", 0);
1817   if (restriction_format[1]) {
1818     restrictioncaps = gst_caps_from_string (restriction_format[0]);
1819     strcaps = g_strdup (restriction_format[1]);
1820   } else {
1821     restrictioncaps = NULL;
1822     strcaps = g_strdup (restriction_format[0]);
1823   }
1824   g_strfreev (restriction_format);
1825
1826   preset_v = g_strsplit (strcaps, "+", 0);
1827   if (preset_v[1]) {
1828     strpresence = preset_v[1];
1829     g_free (strcaps);
1830     strcaps = g_strdup (preset_v[0]);
1831   } else {
1832     strpresence = preset_v[0];
1833   }
1834
1835   strprops_v = g_strsplit (strpresence, "|", 0);
1836   if (strprops_v[1]) {          /* We have a properties */
1837     gchar *endptr;
1838     guint propi;
1839
1840     if (preset_v[1]) {          /* We have preset and properties */
1841       preset_name = g_strdup (strprops_v[0]);
1842     } else {                    /* We have a properties but no preset */
1843       g_free (strcaps);
1844       strcaps = g_strdup (strprops_v[0]);
1845     }
1846
1847     for (propi = 1; strprops_v[propi]; propi++) {
1848       gchar **propv;
1849       gchar *presence_str = NULL;
1850       gchar *prop = strprops_v[propi];
1851       GstStructure *tmpstruct = NULL;
1852
1853       if (gst_structure_validate_name (prop))
1854         tmpstruct = gst_structure_new_from_string (prop);
1855       if (tmpstruct) {
1856         if (element_properties)
1857           gst_structure_free (element_properties);
1858
1859         element_properties = tmpstruct;
1860
1861         continue;
1862       }
1863
1864       propv = g_strsplit (prop, "=", -1);
1865       if (propv[1] && propv[2]) {
1866         g_warning ("Wrong format for property: %s, only 1 `=` is expected",
1867             prop);
1868
1869         return NULL;
1870       }
1871
1872       if (!propv[1]) {
1873         presence_str = propv[0];
1874       } else if (!g_strcmp0 (propv[0], "presence")) {
1875         presence_str = propv[1];
1876       } else if (!g_strcmp0 (propv[0], "variable-framerate")) {
1877         variable_framerate = g_strdup (propv[1]);
1878       } else if (!g_strcmp0 (propv[0], "single-segment")) {
1879         GValue v = G_VALUE_INIT;
1880
1881         g_value_init (&v, G_TYPE_BOOLEAN);
1882         if (!gst_value_deserialize (&v, propv[1])) {
1883           g_warning ("Invalid value for property 'single-segment': %s",
1884               propv[1]);
1885
1886           return NULL;
1887         }
1888
1889         single_segment = g_value_get_boolean (&v);
1890         g_value_reset (&v);
1891       } else {
1892         g_warning ("Unsupported property: %s", propv[0]);
1893         return NULL;
1894       }
1895
1896       if (presence_str) {
1897         presence = g_ascii_strtoll (presence_str, &endptr, 10);
1898
1899         if (endptr == strprops_v[1]) {
1900           g_warning ("Wrong presence %s", presence_str);
1901           return NULL;
1902         }
1903       }
1904     }
1905   } else {                      /* We have no presence */
1906     if (preset_v[1]) {          /* Not presence but preset */
1907       preset_name = g_strdup (preset_v[1]);
1908       g_free (strcaps);
1909       strcaps = g_strdup (preset_v[0]);
1910     }                           /* Else we have no presence nor preset */
1911   }
1912   g_strfreev (strprops_v);
1913   g_strfreev (preset_v);
1914
1915   GST_DEBUG ("Creating preset with restrictions: %" GST_PTR_FORMAT
1916       ", caps: %s, preset %s, presence %d", restrictioncaps, strcaps,
1917       preset_name ? preset_name : "none", presence);
1918
1919   caps = gst_caps_from_string (strcaps);
1920   if (caps) {
1921     profile = create_encoding_profile_from_caps (caps, preset_name,
1922         restrictioncaps, presence, single_segment, NULL, muxers_and_encoders,
1923         raw_audio_caps, raw_video_caps, FALSE);
1924     gst_caps_unref (caps);
1925   }
1926
1927   if (!profile) {
1928     gboolean is_rendering_muxer;
1929
1930     caps = get_profile_format_from_possible_factory_name (strcaps,
1931         &factory_name, restrictioncaps ? NULL : &restrictioncaps,
1932         &is_rendering_muxer);
1933     if (caps) {
1934       profile = create_encoding_profile_from_caps (caps, preset_name,
1935           restrictioncaps, presence, single_segment, factory_name,
1936           muxers_and_encoders, raw_audio_caps, raw_video_caps,
1937           is_rendering_muxer);
1938       gst_caps_unref (caps);
1939     }
1940   }
1941   g_free (preset_name);
1942   g_free (strcaps);
1943
1944   if (restrictioncaps)
1945     gst_caps_unref (restrictioncaps);
1946
1947   if (variable_framerate) {
1948     if (GST_IS_ENCODING_VIDEO_PROFILE (profile)) {
1949       GValue v = {
1950         0,
1951       };
1952       g_value_init (&v, G_TYPE_BOOLEAN);
1953       if (gst_value_deserialize (&v, variable_framerate)) {
1954         gst_encoding_video_profile_set_variableframerate
1955             (GST_ENCODING_VIDEO_PROFILE (profile), g_value_get_boolean (&v));
1956       } else {
1957         GST_WARNING ("Invalid value for variable_framerate: %s",
1958             variable_framerate);
1959
1960       }
1961       g_value_reset (&v);
1962     } else {
1963       GST_WARNING
1964           ("Variable framerate specified on a non video encoding profile");
1965     }
1966
1967     g_free (variable_framerate);
1968   }
1969
1970   if (profile == NULL) {
1971     GST_ERROR ("No way to create a profile for description: %s",
1972         serialized_profile);
1973
1974     return NULL;
1975   }
1976
1977   if (element_properties)
1978     gst_encoding_profile_set_element_properties (profile, element_properties);
1979
1980   return profile;
1981 }
1982
1983 static GstEncodingProfile *
1984 parse_encoding_profile (const gchar * value)
1985 {
1986   GstEncodingProfile *res = NULL;
1987   gchar *caps_str = NULL;
1988   gchar **strcaps_v =
1989       g_regex_split_simple ("(?<!\\\\)(?:\\\\\\\\)*:", value, 0, 0);
1990   guint i;
1991   GList *muxers_and_encoders =
1992       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER |
1993       GST_ELEMENT_FACTORY_TYPE_MUXER,
1994       GST_RANK_MARGINAL);
1995   GstCaps *raw_video_caps = gst_caps_new_empty_simple ("video/x-raw");
1996   GstCaps *raw_audio_caps = gst_caps_new_empty_simple ("audio/x-raw");
1997
1998   /* The regex returns NULL if no ":" found, handle that case. */
1999   if (strcaps_v == NULL)
2000     strcaps_v = g_strsplit (value, ":", 0);
2001
2002   for (i = 0; strcaps_v[i] && *strcaps_v[i]; i++) {
2003     GstEncodingProfile *profile;
2004     caps_str = g_strcompress (strcaps_v[i]);
2005     profile =
2006         create_encoding_stream_profile (caps_str, muxers_and_encoders,
2007         raw_audio_caps, raw_video_caps);
2008
2009     if (!profile) {
2010       GST_ERROR ("Could not create profile for caps: %s", caps_str);
2011       goto error;
2012     }
2013
2014     if (res) {
2015       if (!GST_IS_ENCODING_CONTAINER_PROFILE (res)) {
2016         GST_ERROR ("The first described encoding profile was not a container"
2017             " but you are trying to add more profiles to it. This is not possible");
2018         goto error;
2019       }
2020
2021       if (!gst_encoding_container_profile_add_profile
2022           (GST_ENCODING_CONTAINER_PROFILE (res), profile)) {
2023         GST_ERROR ("Can not add profile for caps: %s", caps_str);
2024         goto error;
2025       }
2026     } else {
2027       res = profile;
2028     }
2029
2030     g_clear_pointer (&caps_str, g_free);
2031   }
2032
2033 done:
2034   g_free (caps_str);
2035   g_strfreev (strcaps_v);
2036   gst_caps_unref (raw_audio_caps);
2037   gst_caps_unref (raw_video_caps);
2038   gst_plugin_feature_list_free (muxers_and_encoders);
2039
2040   return res;
2041
2042 error:
2043   g_clear_object (&res);
2044
2045   goto done;
2046 }
2047
2048 static GstEncodingProfile *
2049 profile_from_string (const gchar * string)
2050 {
2051   GstEncodingProfile *profile;
2052   gchar *filename_end;
2053
2054   profile = combo_search (string);
2055
2056   if (profile)
2057     return profile;
2058
2059   filename_end = g_strrstr (string, ".gep");
2060   if (filename_end) {
2061     GstEncodingTarget *target;
2062     gchar *profilename = NULL, *filename;
2063
2064     if (filename_end[4] == ':')
2065       profilename = g_strdup (&filename_end[5]);
2066
2067     if (filename_end[4] == '\0' || profilename) {
2068       filename = g_strndup (string, filename_end - string + strlen (".gep"));
2069
2070       target = gst_encoding_target_load_from_file (filename, NULL);
2071       if (target) {
2072         profile = gst_encoding_target_get_profile (target,
2073             profilename ? profilename : "default");
2074         gst_encoding_target_unref (target);
2075       }
2076
2077       g_free (profilename);
2078       g_free (filename);
2079     }
2080   }
2081
2082   if (!profile)
2083     profile = parse_encoding_profile (string);
2084
2085   return profile;
2086 }
2087
2088 /* GValue transform function */
2089 static void
2090 string_to_profile_transform (const GValue * src_value, GValue * dest_value)
2091 {
2092   const gchar *profilename;
2093   GstEncodingProfile *profile;
2094
2095   profilename = g_value_get_string (src_value);
2096
2097   profile = profile_from_string (profilename);
2098
2099   if (profile)
2100     g_value_take_object (dest_value, (GObject *) profile);
2101 }
2102
2103 static void
2104 serialize_profile (GString * res, GstEncodingProfile * profile)
2105 {
2106   gchar *tmp;
2107
2108   if (res->len)
2109     g_string_append_c (res, ':');
2110
2111   if (profile->restriction) {
2112     tmp = gst_caps_to_string (profile->restriction);
2113     g_string_append_printf (res, "%s->", tmp);
2114     g_free (tmp);
2115   }
2116
2117   tmp = gst_caps_to_string (profile->format);
2118   g_string_append (res, tmp);
2119
2120   if (profile->presence)
2121     g_string_append_printf (res, "|presence=%d", profile->presence);
2122
2123   if (profile->single_segment)
2124     g_string_append_printf (res, "%ssingle-segment=true",
2125         profile->presence ? "" : "|");
2126
2127   if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
2128     GList *tmp;
2129
2130     for (tmp = GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles; tmp;
2131         tmp = tmp->next)
2132       serialize_profile (res, tmp->data);
2133   }
2134 }
2135
2136 static gchar *
2137 gst_encoding_profile_serialize_valfunc (GValue * value)
2138 {
2139   GString *res = g_string_new (NULL);
2140   GstEncodingProfile *profile = g_value_get_object (value);
2141
2142   serialize_profile (res, profile);
2143
2144   return g_string_free (res, FALSE);
2145 }
2146
2147 static gboolean
2148 gst_encoding_profile_deserialize_valfunc (GValue * value, const gchar * s)
2149 {
2150   GstEncodingProfile *profile;
2151
2152   profile = profile_from_string (s);
2153
2154   if (profile) {
2155     g_value_take_object (value, (GObject *) profile);
2156     return TRUE;
2157   }
2158
2159   return FALSE;
2160 }
2161
2162 static GstEncodingProfile *
2163 create_stream_profile_recurse (GstEncodingProfile * toplevel,
2164     GstDiscovererStreamInfo * sinfo)
2165 {
2166   GstEncodingProfile *profile = NULL;
2167   GstStructure *s;
2168   GstCaps *caps;
2169
2170   caps = gst_discoverer_stream_info_get_caps (sinfo);
2171
2172   /* Should unify this with copy_and_clean_caps() */
2173   caps = gst_caps_make_writable (caps);
2174   s = gst_caps_get_structure (caps, 0);
2175
2176   gst_structure_remove_fields (s, "codec_data", "streamheader", "parsed",
2177       "colorimetry", "framed", "stream-format", "alignment", "tier", "level",
2178       "profile", NULL);
2179
2180   GST_LOG ("Stream: %" GST_PTR_FORMAT, caps);
2181   if (GST_IS_DISCOVERER_AUDIO_INFO (sinfo)) {
2182     profile =
2183         (GstEncodingProfile *) gst_encoding_audio_profile_new (caps, NULL,
2184         NULL, 0);
2185   } else if (GST_IS_DISCOVERER_VIDEO_INFO (sinfo)) {
2186     profile =
2187         (GstEncodingProfile *) gst_encoding_video_profile_new (caps, NULL,
2188         NULL, 0);
2189   } else if (GST_IS_DISCOVERER_CONTAINER_INFO (sinfo)) {
2190     GList *streams, *stream;
2191
2192     streams =
2193         gst_discoverer_container_info_get_streams (GST_DISCOVERER_CONTAINER_INFO
2194         (sinfo));
2195
2196     if (!toplevel || !GST_IS_ENCODING_CONTAINER_PROFILE (toplevel)) {
2197       GstEncodingProfile *prev_toplevel = toplevel;
2198
2199       toplevel = (GstEncodingProfile *)
2200           gst_encoding_container_profile_new ("auto-generated",
2201           "Automatically generated from GstDiscovererInfo", caps, NULL);
2202       if (prev_toplevel)
2203         gst_encoding_container_profile_add_profile
2204             (GST_ENCODING_CONTAINER_PROFILE (toplevel), prev_toplevel);
2205     }
2206
2207     for (stream = streams; stream; stream = stream->next)
2208       create_stream_profile_recurse (toplevel,
2209           (GstDiscovererStreamInfo *) stream->data);
2210     gst_discoverer_stream_info_list_free (streams);
2211   } else {
2212     GST_FIXME ("Ignoring stream of type '%s'",
2213         g_type_name (G_OBJECT_TYPE (sinfo)));
2214     /* subtitles or other ? ignore for now */
2215   }
2216   gst_caps_unref (caps);
2217
2218   if (profile) {
2219     const gchar *stream_id = gst_discoverer_stream_info_get_stream_id (sinfo);
2220
2221     if (stream_id) {
2222       const gchar *subid = strchr (stream_id, '/');
2223
2224       gst_encoding_profile_set_name (profile, subid ? subid : stream_id);
2225     }
2226
2227     if (GST_IS_ENCODING_CONTAINER_PROFILE (toplevel))
2228       gst_encoding_container_profile_add_profile ((GstEncodingContainerProfile
2229               *)
2230           toplevel, profile);
2231   }
2232
2233   if (!toplevel && profile)
2234     toplevel = profile;
2235
2236   sinfo = gst_discoverer_stream_info_get_next (sinfo);
2237   if (sinfo)
2238     return create_stream_profile_recurse (toplevel, sinfo);
2239
2240   return toplevel;
2241 }
2242
2243 static gint
2244 _compare_profile_names (const GstEncodingProfile * a,
2245     const GstEncodingProfile * b)
2246 {
2247   return g_strcmp0 (a->name, b->name);
2248 }
2249
2250 /**
2251  * gst_encoding_profile_from_discoverer:
2252  * @info: (transfer none): The #GstDiscovererInfo to read from
2253  *
2254  * Creates a #GstEncodingProfile matching the formats from the given
2255  * #GstDiscovererInfo. Streams other than audio or video (eg,
2256  * subtitles), are currently ignored.
2257  *
2258  * Returns: (transfer full): The new #GstEncodingProfile or %NULL.
2259  */
2260 GstEncodingProfile *
2261 gst_encoding_profile_from_discoverer (GstDiscovererInfo * info)
2262 {
2263   GstEncodingProfile *profile;
2264   GstDiscovererStreamInfo *sinfo;
2265
2266   if (!info || gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK)
2267     return NULL;
2268
2269   sinfo = gst_discoverer_info_get_stream_info (info);
2270   if (!sinfo)
2271     return NULL;
2272
2273   profile = create_stream_profile_recurse (NULL, sinfo);
2274   if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
2275     if (!gst_encoding_container_profile_get_profiles
2276         (GST_ENCODING_CONTAINER_PROFILE (profile))) {
2277       GST_ERROR ("Failed to add any streams");
2278       g_object_unref (profile);
2279       return NULL;
2280     }
2281     /* Sort by stream ID */
2282     GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles =
2283         g_list_sort (GST_ENCODING_CONTAINER_PROFILE (profile)->encodingprofiles,
2284         (GCompareFunc) _compare_profile_names);
2285
2286   }
2287
2288   return (GstEncodingProfile *) profile;
2289 }
2290
2291 /**
2292  * gst_encoding_profile_copy:
2293  * @self: The #GstEncodingProfile to copy
2294  *
2295  * Makes a deep copy of @self
2296  *
2297  * Returns: (transfer full): The copy of @self
2298  *
2299  * Since: 1.12
2300  */
2301 GstEncodingProfile *
2302 gst_encoding_profile_copy (GstEncodingProfile * self)
2303 {
2304   GstEncodingProfileClass *klass =
2305       (GstEncodingProfileClass *) G_OBJECT_GET_CLASS (self);
2306   GstEncodingProfile *copy =
2307       common_creation (G_OBJECT_TYPE (self), self->format, self->preset,
2308       self->name, self->description, self->restriction, self->presence);
2309
2310   copy->enabled = self->enabled;
2311   copy->allow_dynamic_output = self->allow_dynamic_output;
2312   gst_encoding_profile_set_preset_name (copy, self->preset_name);
2313   gst_encoding_profile_set_description (copy, self->description);
2314
2315   if (klass->copy)
2316     klass->copy (self, copy);
2317
2318   return copy;
2319 }