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