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