Skip to content

Commit

Permalink
encodebin: Add APIs to set element properties on encoding profiles
Browse files Browse the repository at this point in the history
User often want to set encoder properties on encoding profiles,
this introduces a way to easily 'preset' properties when defining the
profile. This uses GstStructure to define those properties the same
way it is done in `splitmux` for example as it makes simple to handle.

This also defines a more complex structure type where we can map a set
of properties to set depending on the muxer/encoder factory that has
been picked by EncodeBin so it is quite flexible.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1002>
  • Loading branch information
thiblahute authored and GStreamer Merge Bot committed Feb 10, 2021
1 parent a8fdaba commit a8fca8d
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 37 deletions.
201 changes: 183 additions & 18 deletions gst-libs/gst/pbutils/encoding-profile.c
Expand Up @@ -30,8 +30,8 @@
*
* Functions to create and handle encoding profiles.
*
* Encoding profiles describe the media types and settings one wishes to use
* for an encoding process. The top-level profiles are commonly
* Encoding profiles describe the media types and settings one wishes to use for
* an encoding process. The top-level profiles are commonly
* #GstEncodingContainerProfile(s) (which contains a user-readable name and
* description along with which container format to use). These, in turn,
* reference one or more #GstEncodingProfile(s) which indicate which encoding
Expand Down Expand Up @@ -101,18 +101,21 @@
*
* ### Setting properties on muxers or on the encoding profile itself
*
* Moreover, you can set extra properties `presence`, `single-segment` and
* `variable-framerate` * of an * encoding profile using the `|presence=` syntax
* as in:
* Moreover, you can set the extra properties:
*
* * `|element-properties,property1=true` (See
* #gst_encoding_profile_set_element_properties)
* * `|presence=true` (See See #gst_encoding_profile_get_presence)
* * `|single-segment=true` (See #gst_encoding_profile_set_single_segment)
* * `|single-segment=true` (See
* #gst_encoding_video_profile_set_variableframerate)
*
* for example:
*
* ```
* video/webm:video/x-vp8|presence=1,variable-framerate=true|single-segment=true:audio/x-vorbis
* video/webm:video/x-vp8|presence=1|element-properties,target-bitrate=500000:audio/x-vorbis
* ```
*
* This field allows specifies the maximum number of times a
* #GstEncodingProfile can be used inside an encodebin. If 0, it is not a
* mandatory stream and can be used as many times as necessary.
*
* ### Enforcing properties to the stream itself (video size, number of audio channels, etc..)
*
* You can also use the `restriction_caps->encoded_format_caps` syntax to
Expand Down Expand Up @@ -297,6 +300,8 @@
#include <string.h>

/* GstEncodingProfile API */
#define PROFILE_LOCK(profile) (g_mutex_lock(&((GstEncodingProfile*)profile)->lock))
#define PROFILE_UNLOCK(profile) (g_mutex_unlock(&((GstEncodingProfile*)profile)->lock))

struct _GstEncodingProfile
{
Expand All @@ -309,10 +314,14 @@ struct _GstEncodingProfile
gchar *preset;
gchar *preset_name;
guint presence;
GstCaps *restriction;
gboolean allow_dynamic_output;
gboolean enabled;
gboolean single_segment;

GMutex lock; // {
GstCaps *restriction;
GstStructure *element_properties;
// }
};

struct _GstEncodingProfileClass
Expand All @@ -326,6 +335,7 @@ enum
{
FIRST_PROPERTY,
PROP_RESTRICTION_CAPS,
PROP_ELEMENT_PROPERTIES,
LAST_PROPERTY
};

Expand Down Expand Up @@ -391,6 +401,11 @@ _encoding_profile_get_property (GObject * object, guint prop_id,
case PROP_RESTRICTION_CAPS:
gst_value_set_caps (value, prof->restriction);
break;
case PROP_ELEMENT_PROPERTIES:
PROFILE_LOCK (prof);
gst_value_set_structure (value, prof->element_properties);
PROFILE_UNLOCK (prof);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand All @@ -408,6 +423,14 @@ _encoding_profile_set_property (GObject * object, guint prop_id,
gst_encoding_profile_set_restriction (prof, gst_caps_copy
(gst_value_get_caps (value)));
break;
case PROP_ELEMENT_PROPERTIES:
{
const GstStructure *structure = gst_value_get_structure (value);

gst_encoding_profile_set_element_properties (prof,
structure ? gst_structure_copy (structure) : NULL);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -441,11 +464,30 @@ gst_encoding_profile_class_init (GstEncodingProfileClass * klass)
_properties[PROP_RESTRICTION_CAPS] =
g_param_spec_boxed ("restriction-caps", "Restriction caps",
"The restriction caps to use", GST_TYPE_CAPS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);

g_object_class_install_property (gobject_class,
PROP_RESTRICTION_CAPS, _properties[PROP_RESTRICTION_CAPS]);

G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

/**
* GstEncodingProfile:element-properties:
*
* A #GstStructure defining the properties to be set to the element
* the profile represents.
*
* For example for `av1enc`:
*
* ```
* element-properties,row-mt=true, end-usage=vbr
* ```
*
* Since: 1.20
*/
_properties[PROP_ELEMENT_PROPERTIES] =
g_param_spec_boxed ("element-properties", "Element properties",
"The element properties to use. "
"Example: {properties,boolean-prop=true,string-prop=\"hi\"}.",
GST_TYPE_STRUCTURE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

g_object_class_install_properties (gobject_class, LAST_PROPERTY, _properties);
}

/**
Expand Down Expand Up @@ -791,6 +833,84 @@ gst_encoding_profile_set_restriction (GstEncodingProfile * profile,
_properties[PROP_RESTRICTION_CAPS]);
}

/**
* gst_encoding_profile_set_element_properties:
* @self: a #GstEncodingProfile
* @element_properties: (transfer full): A #GstStructure defining the properties
* to be set to the element the profile represents.
*
* This allows setting the muxing/encoding element properties.
*
* **Set properties generically**
*
* ``` properties
* [element-properties, boolean-prop=true, string-prop="hi"]
* ```
*
* **Mapping properties with well known element factories**
*
* ``` properties
* element-properties-map, map = {
* [openh264enc, gop-size=32, ],
* [x264enc, key-int-max=32, tune=zerolatency],
* }
* ```
*
* Since: 1.20
*/
void
gst_encoding_profile_set_element_properties (GstEncodingProfile * self,
GstStructure * element_properties)
{
g_return_if_fail (GST_IS_ENCODING_PROFILE (self));
g_return_if_fail (!element_properties
|| GST_IS_STRUCTURE (element_properties));

#ifndef G_DISABLE_CHECKS
if (element_properties &&
(gst_structure_has_name (element_properties, "element-properties-map")
|| gst_structure_has_name (element_properties, "properties-map")
|| gst_structure_has_name (element_properties, "map")))
g_return_if_fail (gst_structure_has_field_typed (element_properties, "map",
GST_TYPE_LIST));
#endif

PROFILE_LOCK (self);
if (self->element_properties)
gst_structure_free (self->element_properties);
if (element_properties)
self->element_properties = element_properties;
else
self->element_properties = NULL;
PROFILE_UNLOCK (self);

g_object_notify_by_pspec (G_OBJECT (self),
_properties[PROP_ELEMENT_PROPERTIES]);
}

/**
* gst_encoding_profile_get_element_properties:
* @self: a #GstEncodingProfile
*
* Returns: (transfer full) (nullable): The properties that are going to be set on the underlying element
*
* Since: 1.20
*/
GstStructure *
gst_encoding_profile_get_element_properties (GstEncodingProfile * self)
{
GstStructure *res = NULL;

g_return_val_if_fail (GST_IS_ENCODING_PROFILE (self), NULL);

PROFILE_LOCK (self);
if (self->element_properties)
res = gst_structure_copy (self->element_properties);
PROFILE_UNLOCK (self);

return res;
}

/* Container profiles */

struct _GstEncodingContainerProfile
Expand Down Expand Up @@ -1648,6 +1768,30 @@ create_encoding_profile_from_caps (GstCaps * caps, gchar * preset_name,
return profile;
}

static gboolean
gst_structure_validate_name (const gchar * name)
{
const gchar *s;

g_return_val_if_fail (name != NULL, FALSE);

if (G_UNLIKELY (!g_ascii_isalpha (*name)))
return FALSE;

/* FIXME: test name string more */
s = &name[1];
while (*s && (g_ascii_isalnum (*s) || strchr ("/-_.:+", *s) != NULL))
s++;

if (*s == ',')
return TRUE;

if (G_UNLIKELY (*s != '\0'))
return FALSE;

return TRUE;
}

static GstEncodingProfile *
create_encoding_stream_profile (gchar * serialized_profile,
GList * muxers_and_encoders, GstCaps * raw_audio_caps,
Expand All @@ -1659,6 +1803,7 @@ create_encoding_stream_profile (gchar * serialized_profile,
gchar *strcaps, *strpresence, **strprops_v, **restriction_format,
**preset_v, *preset_name = NULL, *factory_name = NULL,
*variable_framerate = NULL;
GstStructure *element_properties = NULL;
GstCaps *restrictioncaps = NULL;
GstEncodingProfile *profile = NULL;

Expand Down Expand Up @@ -1694,12 +1839,26 @@ create_encoding_stream_profile (gchar * serialized_profile,
}

for (propi = 1; strprops_v[propi]; propi++) {
gchar **propv = g_strsplit (strprops_v[propi], "=", -1);
gchar **propv;
gchar *presence_str = NULL;
gchar *prop = strprops_v[propi];
GstStructure *tmpstruct = NULL;

if (gst_structure_validate_name (prop))
tmpstruct = gst_structure_new_from_string (prop);
if (tmpstruct) {
if (element_properties)
gst_structure_free (element_properties);

element_properties = tmpstruct;

continue;
}

propv = g_strsplit (prop, "=", -1);
if (propv[1] && propv[2]) {
g_warning ("Wrong format for property: %s, only 1 `=` is expected",
strprops_v[propi]);
prop);

return NULL;
}
Expand All @@ -1723,6 +1882,9 @@ create_encoding_stream_profile (gchar * serialized_profile,

single_segment = g_value_get_boolean (&v);
g_value_reset (&v);
} else {
g_warning ("Unsupported property: %s", propv[0]);
return NULL;
}

if (presence_str) {
Expand Down Expand Up @@ -1806,6 +1968,9 @@ create_encoding_stream_profile (gchar * serialized_profile,
return NULL;
}

if (element_properties)
gst_encoding_profile_set_element_properties (profile, element_properties);

return profile;
}

Expand Down
9 changes: 8 additions & 1 deletion gst-libs/gst/pbutils/encoding-profile.h
Expand Up @@ -264,7 +264,14 @@ GST_PBUTILS_API
GstEncodingProfile * gst_encoding_profile_from_discoverer (GstDiscovererInfo *info);

GST_PBUTILS_API
GstEncodingProfile * gst_encoding_profile_copy (GstEncodingProfile *self);
GstEncodingProfile * gst_encoding_profile_copy (GstEncodingProfile *self);

GST_PBUTILS_API
void gst_encoding_profile_set_element_properties (GstEncodingProfile *self,
GstStructure *element_properties);

GST_PBUTILS_API
GstStructure *gst_encoding_profile_get_element_properties (GstEncodingProfile *self);

G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstEncodingAudioProfile, gst_object_unref)

Expand Down

0 comments on commit a8fca8d

Please sign in to comment.