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