Coverage Report

Created: 2026-08-25 07:00

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