mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
c53ea138c6
* Don't mention explicitly that API is MT safe, this implies that other API is not. GStreamer API is assumed to be MT safe, thread safety should only be explicitly mentioned when API is *not* MT safe * Document virtual methods in standalone comments, in order to properly annotate them * Don't repeat what annotations are stating with respect to ownership transfer, nullability * Misc cleanup / typo fixes / addition of links Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/755>
860 lines
20 KiB
C
860 lines
20 KiB
C
/* GStreamer
|
|
* Copyright (C) 2013 Collabora Ltd.
|
|
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:gstcapsfeatures
|
|
* @title: GstCapsFeatures
|
|
* @short_description: A set of features in caps
|
|
* @see_also: #GstCaps
|
|
*
|
|
* #GstCapsFeatures can optionally be set on a #GstCaps to add requirements
|
|
* for additional features for a specific #GstStructure. Caps structures with
|
|
* the same name but with a non-equal set of caps features are not compatible.
|
|
* If a pad supports multiple sets of features it has to add multiple equal
|
|
* structures with different feature sets to the caps.
|
|
*
|
|
* Empty #GstCapsFeatures are equivalent with the #GstCapsFeatures that only
|
|
* contain #GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY. ANY #GstCapsFeatures as
|
|
* created by gst_caps_features_new_any() are equal to any other #GstCapsFeatures
|
|
* and can be used to specify that any #GstCapsFeatures would be supported, e.g.
|
|
* for elements that don't touch buffer memory. #GstCaps with ANY #GstCapsFeatures
|
|
* are considered non-fixed and during negotiation some #GstCapsFeatures have
|
|
* to be selected.
|
|
*
|
|
* Examples for caps features would be the requirement of a specific #GstMemory
|
|
* types or the requirement of having a specific #GstMeta on the buffer. Features
|
|
* are given as a string of the format `memory:GstMemoryTypeName` or
|
|
* `meta:GstMetaAPIName`.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include "gst_private.h"
|
|
#include "gstcapsfeatures.h"
|
|
#include <gst/gst.h>
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (gst_caps_features_debug);
|
|
#define GST_CAT_DEFAULT gst_caps_features_debug
|
|
|
|
struct _GstCapsFeatures
|
|
{
|
|
GType type;
|
|
gint *parent_refcount;
|
|
GArray *array;
|
|
gboolean is_any;
|
|
};
|
|
|
|
GType _gst_caps_features_type = 0;
|
|
static gint static_caps_features_parent_refcount = G_MAXINT;
|
|
GstCapsFeatures *_gst_caps_features_any = NULL;
|
|
GstCapsFeatures *_gst_caps_features_memory_system_memory = NULL;
|
|
static GQuark _gst_caps_feature_memory_system_memory = 0;
|
|
|
|
G_DEFINE_BOXED_TYPE (GstCapsFeatures, gst_caps_features,
|
|
gst_caps_features_copy, gst_caps_features_free);
|
|
|
|
#define IS_MUTABLE(features) \
|
|
(!features->parent_refcount || \
|
|
g_atomic_int_get (features->parent_refcount) == 1)
|
|
|
|
static void
|
|
gst_caps_features_transform_to_string (const GValue * src_value,
|
|
GValue * dest_value);
|
|
|
|
void
|
|
_priv_gst_caps_features_initialize (void)
|
|
{
|
|
GST_DEBUG_CATEGORY_INIT (gst_caps_features_debug, "caps-features", 0,
|
|
"GstCapsFeatures debug");
|
|
|
|
_gst_caps_features_type = gst_caps_features_get_type ();
|
|
_gst_caps_feature_memory_system_memory =
|
|
g_quark_from_static_string (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
|
|
|
|
g_value_register_transform_func (_gst_caps_features_type, G_TYPE_STRING,
|
|
gst_caps_features_transform_to_string);
|
|
|
|
_gst_caps_features_any = gst_caps_features_new_any ();
|
|
gst_caps_features_set_parent_refcount (_gst_caps_features_any,
|
|
&static_caps_features_parent_refcount);
|
|
_gst_caps_features_memory_system_memory =
|
|
gst_caps_features_new_id (_gst_caps_feature_memory_system_memory, 0);
|
|
gst_caps_features_set_parent_refcount
|
|
(_gst_caps_features_memory_system_memory,
|
|
&static_caps_features_parent_refcount);
|
|
}
|
|
|
|
void
|
|
_priv_gst_caps_features_cleanup (void)
|
|
{
|
|
gst_caps_features_set_parent_refcount (_gst_caps_features_any, NULL);
|
|
gst_caps_features_free (_gst_caps_features_any);
|
|
_gst_caps_features_any = NULL;
|
|
gst_caps_features_set_parent_refcount
|
|
(_gst_caps_features_memory_system_memory, NULL);
|
|
gst_caps_features_free (_gst_caps_features_memory_system_memory);
|
|
_gst_caps_features_memory_system_memory = NULL;
|
|
}
|
|
|
|
/**
|
|
* gst_is_caps_features:
|
|
*
|
|
* Checks if @obj is a #GstCapsFeatures
|
|
*
|
|
* Returns: %TRUE if @obj is a #GstCapsFeatures %FALSE otherwise
|
|
*/
|
|
gboolean
|
|
gst_is_caps_features (gconstpointer obj)
|
|
{
|
|
const GstCapsFeatures *features = obj;
|
|
|
|
return (obj != NULL && features->type == _gst_caps_features_type);
|
|
}
|
|
|
|
static gboolean
|
|
gst_caps_feature_name_is_valid (const gchar * feature)
|
|
{
|
|
#ifndef G_DISABLE_CHECKS
|
|
while (TRUE) {
|
|
if (g_ascii_isalpha (*feature))
|
|
feature++;
|
|
else if (*feature == ':')
|
|
break;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
if (*feature != ':')
|
|
return FALSE;
|
|
|
|
feature++;
|
|
if (*feature == '\0' || !g_ascii_isalpha (*feature))
|
|
return FALSE;
|
|
|
|
while (TRUE) {
|
|
if (g_ascii_isalnum (*feature))
|
|
feature++;
|
|
else if (*feature == '\0')
|
|
break;
|
|
else
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_new_empty:
|
|
*
|
|
* Creates a new, empty #GstCapsFeatures.
|
|
*
|
|
* Returns: (transfer full): a new, empty #GstCapsFeatures
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_new_empty (void)
|
|
{
|
|
GstCapsFeatures *features;
|
|
|
|
features = g_slice_new (GstCapsFeatures);
|
|
features->type = _gst_caps_features_type;
|
|
features->parent_refcount = NULL;
|
|
features->array = g_array_new (FALSE, FALSE, sizeof (GQuark));
|
|
features->is_any = FALSE;
|
|
|
|
GST_TRACE ("created caps features %p", features);
|
|
|
|
return features;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_new_any:
|
|
*
|
|
* Creates a new, ANY #GstCapsFeatures. This will be equal
|
|
* to any other #GstCapsFeatures but caps with these are
|
|
* unfixed.
|
|
*
|
|
* Returns: (transfer full): a new, ANY #GstCapsFeatures
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_new_any (void)
|
|
{
|
|
GstCapsFeatures *features;
|
|
|
|
features = gst_caps_features_new_empty ();
|
|
features->is_any = TRUE;
|
|
|
|
return features;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_new:
|
|
* @feature1: name of first feature to set
|
|
* @...: additional features
|
|
*
|
|
* Creates a new #GstCapsFeatures with the given features.
|
|
* The last argument must be %NULL.
|
|
*
|
|
* Returns: (transfer full): a new, empty #GstCapsFeatures
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_new (const gchar * feature1, ...)
|
|
{
|
|
GstCapsFeatures *features;
|
|
va_list varargs;
|
|
|
|
g_return_val_if_fail (feature1 != NULL, NULL);
|
|
|
|
va_start (varargs, feature1);
|
|
features = gst_caps_features_new_valist (feature1, varargs);
|
|
va_end (varargs);
|
|
|
|
return features;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_new_valist:
|
|
* @feature1: name of first feature to set
|
|
* @varargs: variable argument list
|
|
*
|
|
* Creates a new #GstCapsFeatures with the given features.
|
|
*
|
|
* Returns: (transfer full): a new, empty #GstCapsFeatures
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_new_valist (const gchar * feature1, va_list varargs)
|
|
{
|
|
GstCapsFeatures *features;
|
|
|
|
g_return_val_if_fail (feature1 != NULL, NULL);
|
|
|
|
features = gst_caps_features_new_empty ();
|
|
|
|
while (feature1) {
|
|
gst_caps_features_add (features, feature1);
|
|
feature1 = va_arg (varargs, const gchar *);
|
|
}
|
|
|
|
return features;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_new_id:
|
|
* @feature1: name of first feature to set
|
|
* @...: additional features
|
|
*
|
|
* Creates a new #GstCapsFeatures with the given features.
|
|
* The last argument must be 0.
|
|
*
|
|
* Returns: (transfer full): a new, empty #GstCapsFeatures
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_new_id (GQuark feature1, ...)
|
|
{
|
|
GstCapsFeatures *features;
|
|
va_list varargs;
|
|
|
|
g_return_val_if_fail (feature1 != 0, NULL);
|
|
|
|
va_start (varargs, feature1);
|
|
features = gst_caps_features_new_id_valist (feature1, varargs);
|
|
va_end (varargs);
|
|
|
|
return features;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_new_id_valist:
|
|
* @feature1: name of first feature to set
|
|
* @varargs: variable argument list
|
|
*
|
|
* Creates a new #GstCapsFeatures with the given features.
|
|
*
|
|
* Returns: (transfer full): a new, empty #GstCapsFeatures
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_new_id_valist (GQuark feature1, va_list varargs)
|
|
{
|
|
GstCapsFeatures *features;
|
|
|
|
g_return_val_if_fail (feature1 != 0, NULL);
|
|
|
|
features = gst_caps_features_new_empty ();
|
|
|
|
while (feature1) {
|
|
gst_caps_features_add_id (features, feature1);
|
|
feature1 = va_arg (varargs, GQuark);
|
|
}
|
|
|
|
return features;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_set_parent_refcount:
|
|
* @features: a #GstCapsFeatures
|
|
* @refcount: (in): a pointer to the parent's refcount
|
|
*
|
|
* Sets the parent_refcount field of #GstCapsFeatures. This field is used to
|
|
* determine whether a caps features is mutable or not. This function should only be
|
|
* called by code implementing parent objects of #GstCapsFeatures, as described in
|
|
* [the MT refcounting design document](additional/design/MT-refcounting.md).
|
|
*
|
|
* Returns: %TRUE if the parent refcount could be set.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
gboolean
|
|
gst_caps_features_set_parent_refcount (GstCapsFeatures * features,
|
|
gint * refcount)
|
|
{
|
|
g_return_val_if_fail (features != NULL, FALSE);
|
|
|
|
/* if we have a parent_refcount already, we can only clear
|
|
* if with a NULL refcount */
|
|
if (features->parent_refcount) {
|
|
if (refcount != NULL) {
|
|
g_return_val_if_fail (refcount == NULL, FALSE);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
if (refcount == NULL) {
|
|
g_return_val_if_fail (refcount != NULL, FALSE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
features->parent_refcount = refcount;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_copy:
|
|
* @features: a #GstCapsFeatures to duplicate
|
|
*
|
|
* Duplicates a #GstCapsFeatures and all its values.
|
|
*
|
|
* Returns: (transfer full): a new #GstCapsFeatures.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_copy (const GstCapsFeatures * features)
|
|
{
|
|
GstCapsFeatures *copy;
|
|
guint i, n;
|
|
|
|
g_return_val_if_fail (features != NULL, NULL);
|
|
|
|
copy = gst_caps_features_new_empty ();
|
|
n = gst_caps_features_get_size (features);
|
|
for (i = 0; i < n; i++)
|
|
gst_caps_features_add_id (copy, gst_caps_features_get_nth_id (features, i));
|
|
copy->is_any = features->is_any;
|
|
|
|
return copy;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_free:
|
|
* @features: (in) (transfer full): the #GstCapsFeatures to free
|
|
*
|
|
* Frees a #GstCapsFeatures and all its values. The caps features must not
|
|
* have a parent when this function is called.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
gst_caps_features_free (GstCapsFeatures * features)
|
|
{
|
|
g_return_if_fail (features != NULL);
|
|
g_return_if_fail (features->parent_refcount == NULL);
|
|
|
|
g_array_free (features->array, TRUE);
|
|
#ifdef USE_POISONING
|
|
memset (features, 0xff, sizeof (GstCapsFeatures));
|
|
#endif
|
|
GST_TRACE ("free caps features %p", features);
|
|
|
|
g_slice_free (GstCapsFeatures, features);
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_to_string:
|
|
* @features: a #GstCapsFeatures
|
|
*
|
|
* Converts @features to a human-readable string representation.
|
|
*
|
|
* For debugging purposes its easier to do something like this:
|
|
*
|
|
* ``` C
|
|
* GST_LOG ("features is %" GST_PTR_FORMAT, features);
|
|
* ```
|
|
*
|
|
* This prints the features in human readable form.
|
|
*
|
|
* Returns: (transfer full): a pointer to string allocated by g_malloc().
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
gchar *
|
|
gst_caps_features_to_string (const GstCapsFeatures * features)
|
|
{
|
|
GString *s;
|
|
|
|
g_return_val_if_fail (features != NULL, NULL);
|
|
|
|
s = g_string_sized_new (FEATURES_ESTIMATED_STRING_LEN (features));
|
|
|
|
priv_gst_caps_features_append_to_gstring (features, s);
|
|
|
|
return g_string_free (s, FALSE);
|
|
}
|
|
|
|
void
|
|
priv_gst_caps_features_append_to_gstring (const GstCapsFeatures * features,
|
|
GString * s)
|
|
{
|
|
guint i, n;
|
|
|
|
g_return_if_fail (features != NULL);
|
|
|
|
if (features->array->len == 0 && features->is_any) {
|
|
g_string_append (s, "ANY");
|
|
return;
|
|
}
|
|
|
|
n = features->array->len;
|
|
for (i = 0; i < n; i++) {
|
|
GQuark *quark = &g_array_index (features->array, GQuark, i);
|
|
|
|
g_string_append (s, g_quark_to_string (*quark));
|
|
if (i + 1 < n)
|
|
g_string_append (s, ", ");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_from_string:
|
|
* @features: a string representation of a #GstCapsFeatures.
|
|
*
|
|
* Creates a #GstCapsFeatures from a string representation.
|
|
*
|
|
* Returns: (transfer full) (nullable): a new #GstCapsFeatures or
|
|
* %NULL when the string could not be parsed.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstCapsFeatures *
|
|
gst_caps_features_from_string (const gchar * features)
|
|
{
|
|
GstCapsFeatures *ret;
|
|
gboolean escape = FALSE;
|
|
const gchar *features_orig = features;
|
|
const gchar *feature;
|
|
|
|
ret = gst_caps_features_new_empty ();
|
|
|
|
if (!features || *features == '\0')
|
|
return ret;
|
|
|
|
if (strcmp (features, "ANY") == 0) {
|
|
ret->is_any = TRUE;
|
|
return ret;
|
|
}
|
|
|
|
/* Skip trailing spaces */
|
|
while (*features == ' ')
|
|
features++;
|
|
|
|
feature = features;
|
|
while (TRUE) {
|
|
gchar c = *features;
|
|
|
|
if (c == '\\') {
|
|
escape = TRUE;
|
|
features++;
|
|
continue;
|
|
} else if ((!escape && c == ',') || c == '\0') {
|
|
guint len = features - feature + 1;
|
|
gchar *tmp;
|
|
gchar *p;
|
|
|
|
if (len == 1) {
|
|
g_warning ("Failed deserialize caps features '%s'", features_orig);
|
|
gst_caps_features_free (ret);
|
|
return NULL;
|
|
}
|
|
|
|
tmp = g_malloc (len);
|
|
memcpy (tmp, feature, len - 1);
|
|
tmp[len - 1] = '\0';
|
|
|
|
p = tmp + len - 1;
|
|
while (*p == ' ') {
|
|
*p = '\0';
|
|
p--;
|
|
}
|
|
|
|
if (strstr (tmp, " ") != NULL || *tmp == '\0') {
|
|
g_free (tmp);
|
|
g_warning ("Failed deserialize caps features '%s'", features_orig);
|
|
gst_caps_features_free (ret);
|
|
return NULL;
|
|
}
|
|
|
|
gst_caps_features_add (ret, tmp);
|
|
g_free (tmp);
|
|
|
|
if (c == '\0')
|
|
break;
|
|
|
|
/* Skip to the next value */
|
|
features++;
|
|
while (*features == ' ')
|
|
features++;
|
|
feature = features;
|
|
} else {
|
|
escape = FALSE;
|
|
features++;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_get_size:
|
|
* @features: a #GstCapsFeatures.
|
|
*
|
|
* Returns the number of features in @features.
|
|
*
|
|
* Returns: The number of features in @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
guint
|
|
gst_caps_features_get_size (const GstCapsFeatures * features)
|
|
{
|
|
g_return_val_if_fail (features != NULL, 0);
|
|
|
|
return features->array->len;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_get_nth:
|
|
* @features: a #GstCapsFeatures.
|
|
* @i: index of the feature
|
|
*
|
|
* Returns the @i-th feature of @features.
|
|
*
|
|
* Returns: (nullable): The @i-th feature of @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
const gchar *
|
|
gst_caps_features_get_nth (const GstCapsFeatures * features, guint i)
|
|
{
|
|
const gchar *feature;
|
|
GQuark quark;
|
|
|
|
g_return_val_if_fail (features != NULL, NULL);
|
|
|
|
quark = gst_caps_features_get_nth_id (features, i);
|
|
if (!quark)
|
|
return NULL;
|
|
|
|
feature = g_quark_to_string (quark);
|
|
return feature;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_get_nth_id:
|
|
* @features: a #GstCapsFeatures.
|
|
* @i: index of the feature
|
|
*
|
|
* Returns the @i-th feature of @features.
|
|
*
|
|
* Returns: The @i-th feature of @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GQuark
|
|
gst_caps_features_get_nth_id (const GstCapsFeatures * features, guint i)
|
|
{
|
|
GQuark *quark;
|
|
|
|
g_return_val_if_fail (features != NULL, 0);
|
|
g_return_val_if_fail (i < features->array->len, 0);
|
|
|
|
quark = &g_array_index (features->array, GQuark, i);
|
|
|
|
return *quark;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_contains:
|
|
* @features: a #GstCapsFeatures.
|
|
* @feature: a feature
|
|
*
|
|
* Checks if @features contains @feature.
|
|
*
|
|
* Returns: %TRUE if @features contains @feature.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
gboolean
|
|
gst_caps_features_contains (const GstCapsFeatures * features,
|
|
const gchar * feature)
|
|
{
|
|
g_return_val_if_fail (features != NULL, FALSE);
|
|
g_return_val_if_fail (feature != NULL, FALSE);
|
|
|
|
return gst_caps_features_contains_id (features,
|
|
g_quark_from_string (feature));
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_contains_id:
|
|
* @features: a #GstCapsFeatures.
|
|
* @feature: a feature
|
|
*
|
|
* Checks if @features contains @feature.
|
|
*
|
|
* Returns: %TRUE if @features contains @feature.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
gboolean
|
|
gst_caps_features_contains_id (const GstCapsFeatures * features, GQuark feature)
|
|
{
|
|
guint i, n;
|
|
|
|
g_return_val_if_fail (features != NULL, FALSE);
|
|
g_return_val_if_fail (feature != 0, FALSE);
|
|
|
|
if (features->is_any)
|
|
return TRUE;
|
|
|
|
n = features->array->len;
|
|
if (n == 0)
|
|
return feature == _gst_caps_feature_memory_system_memory;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
if (gst_caps_features_get_nth_id (features, i) == feature)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_is_equal:
|
|
* @features1: a #GstCapsFeatures.
|
|
* @features2: a #GstCapsFeatures.
|
|
*
|
|
* Checks if @features1 and @features2 are equal.
|
|
*
|
|
* Returns: %TRUE if @features1 and @features2 are equal.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
gboolean
|
|
gst_caps_features_is_equal (const GstCapsFeatures * features1,
|
|
const GstCapsFeatures * features2)
|
|
{
|
|
guint i, n;
|
|
|
|
g_return_val_if_fail (features1 != NULL, FALSE);
|
|
g_return_val_if_fail (features2 != NULL, FALSE);
|
|
|
|
if (features1->is_any || features2->is_any)
|
|
return TRUE;
|
|
|
|
/* Check for the sysmem==empty case */
|
|
if (features1->array->len == 0 && features2->array->len == 0)
|
|
return TRUE;
|
|
if (features1->array->len == 0 && features2->array->len == 1
|
|
&& gst_caps_features_contains_id (features2,
|
|
_gst_caps_feature_memory_system_memory))
|
|
return TRUE;
|
|
if (features2->array->len == 0 && features1->array->len == 1
|
|
&& gst_caps_features_contains_id (features1,
|
|
_gst_caps_feature_memory_system_memory))
|
|
return TRUE;
|
|
|
|
if (features1->array->len != features2->array->len)
|
|
return FALSE;
|
|
|
|
n = features1->array->len;
|
|
for (i = 0; i < n; i++)
|
|
if (!gst_caps_features_contains_id (features2,
|
|
gst_caps_features_get_nth_id (features1, i)))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_is_any:
|
|
* @features: a #GstCapsFeatures.
|
|
*
|
|
* Checks if @features is %GST_CAPS_FEATURES_ANY.
|
|
*
|
|
* Returns: %TRUE if @features is %GST_CAPS_FEATURES_ANY.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
gboolean
|
|
gst_caps_features_is_any (const GstCapsFeatures * features)
|
|
{
|
|
g_return_val_if_fail (features != NULL, FALSE);
|
|
|
|
return features->is_any;
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_add:
|
|
* @features: a #GstCapsFeatures.
|
|
* @feature: a feature.
|
|
*
|
|
* Adds @feature to @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
gst_caps_features_add (GstCapsFeatures * features, const gchar * feature)
|
|
{
|
|
g_return_if_fail (features != NULL);
|
|
g_return_if_fail (IS_MUTABLE (features));
|
|
g_return_if_fail (feature != NULL);
|
|
g_return_if_fail (!features->is_any);
|
|
|
|
gst_caps_features_add_id (features, g_quark_from_string (feature));
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_add_id:
|
|
* @features: a #GstCapsFeatures.
|
|
* @feature: a feature.
|
|
*
|
|
* Adds @feature to @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
gst_caps_features_add_id (GstCapsFeatures * features, GQuark feature)
|
|
{
|
|
g_return_if_fail (features != NULL);
|
|
g_return_if_fail (IS_MUTABLE (features));
|
|
g_return_if_fail (feature != 0);
|
|
g_return_if_fail (!features->is_any);
|
|
|
|
if (!gst_caps_feature_name_is_valid (g_quark_to_string (feature))) {
|
|
g_warning ("Invalid caps feature name: %s", g_quark_to_string (feature));
|
|
return;
|
|
}
|
|
|
|
/* If features is empty it will contain sysmem, however
|
|
* we want to add it explicitly if it is attempted to be
|
|
* added as first features
|
|
*/
|
|
if (features->array->len > 0
|
|
&& gst_caps_features_contains_id (features, feature))
|
|
return;
|
|
|
|
g_array_append_val (features->array, feature);
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_remove:
|
|
* @features: a #GstCapsFeatures.
|
|
* @feature: a feature.
|
|
*
|
|
* Removes @feature from @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
gst_caps_features_remove (GstCapsFeatures * features, const gchar * feature)
|
|
{
|
|
g_return_if_fail (features != NULL);
|
|
g_return_if_fail (IS_MUTABLE (features));
|
|
g_return_if_fail (feature != NULL);
|
|
|
|
gst_caps_features_remove_id (features, g_quark_from_string (feature));
|
|
}
|
|
|
|
/**
|
|
* gst_caps_features_remove_id:
|
|
* @features: a #GstCapsFeatures.
|
|
* @feature: a feature.
|
|
*
|
|
* Removes @feature from @features.
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
gst_caps_features_remove_id (GstCapsFeatures * features, GQuark feature)
|
|
{
|
|
guint i, n;
|
|
|
|
g_return_if_fail (features != NULL);
|
|
g_return_if_fail (IS_MUTABLE (features));
|
|
g_return_if_fail (feature != 0);
|
|
|
|
n = features->array->len;
|
|
for (i = 0; i < n; i++) {
|
|
GQuark quark = gst_caps_features_get_nth_id (features, i);
|
|
|
|
if (quark == feature) {
|
|
g_array_remove_index_fast (features->array, i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_caps_features_transform_to_string (const GValue * src_value,
|
|
GValue * dest_value)
|
|
{
|
|
g_return_if_fail (src_value != NULL);
|
|
g_return_if_fail (dest_value != NULL);
|
|
|
|
dest_value->data[0].v_pointer =
|
|
gst_caps_features_to_string (src_value->data[0].v_pointer);
|
|
}
|