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