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