caps: Add new data type for handling caps features to the caps

These are meant to specify features in caps that are required
for a specific structure, for example a specific memory type
or meta.

Semantically they could be though of as an extension of the media
type name of the structures and are handled exactly like that.
This commit is contained in:
Sebastian Dröge 2013-03-30 15:35:19 +01:00
parent caa06788c3
commit 7477b25df5
18 changed files with 1770 additions and 116 deletions

View file

@ -65,6 +65,7 @@ Windows. It is released under the GNU Library General Public License
<xi:include href="xml/gstbufferpool.xml" /> <xi:include href="xml/gstbufferpool.xml" />
<xi:include href="xml/gstbus.xml" /> <xi:include href="xml/gstbus.xml" />
<xi:include href="xml/gstcaps.xml" /> <xi:include href="xml/gstcaps.xml" />
<xi:include href="xml/gstcapsfeatures.xml" />
<xi:include href="xml/gstsample.xml" /> <xi:include href="xml/gstsample.xml" />
<xi:include href="xml/gstchildproxy.xml" /> <xi:include href="xml/gstchildproxy.xml" />
<xi:include href="xml/gstclock.xml" /> <xi:include href="xml/gstclock.xml" />

View file

@ -403,11 +403,15 @@ gst_static_caps_cleanup
gst_caps_append gst_caps_append
gst_caps_merge gst_caps_merge
gst_caps_append_structure gst_caps_append_structure
gst_caps_append_structure_full
gst_caps_remove_structure gst_caps_remove_structure
gst_caps_steal_structure gst_caps_steal_structure
gst_caps_merge_structure gst_caps_merge_structure
gst_caps_merge_structure_full
gst_caps_get_size gst_caps_get_size
gst_caps_get_structure gst_caps_get_structure
gst_caps_get_features
gst_caps_set_features
gst_caps_set_value gst_caps_set_value
gst_caps_set_simple gst_caps_set_simple
gst_caps_set_simple_valist gst_caps_set_simple_valist
@ -420,6 +424,7 @@ gst_caps_is_strictly_equal
gst_caps_is_always_compatible gst_caps_is_always_compatible
gst_caps_is_subset gst_caps_is_subset
gst_caps_is_subset_structure gst_caps_is_subset_structure
gst_caps_is_subset_structure_full
gst_caps_can_intersect gst_caps_can_intersect
gst_caps_intersect gst_caps_intersect
gst_caps_intersect_full gst_caps_intersect_full
@ -448,6 +453,48 @@ gst_caps_get_type
gst_caps_intersect_mode_get_type gst_caps_intersect_mode_get_type
</SECTION> </SECTION>
<SECTION>
<FILE>gstcapsfeatures</FILE>
<TITLE>GstCapsFeatures</TITLE>
GstCapsFeatures
gst_caps_features_new
gst_caps_features_new_empty
gst_caps_features_new_id
gst_caps_features_new_id_valist
gst_caps_features_new_valist
gst_caps_features_copy
gst_caps_features_free
gst_caps_features_from_string
gst_caps_features_to_string
gst_caps_features_set_parent_refcount
gst_caps_features_is_equal
gst_caps_features_contains
gst_caps_features_contains_id
gst_caps_features_get_size
gst_caps_features_get_nth
gst_caps_features_get_nth_id
gst_caps_features_add
gst_caps_features_add_id
gst_caps_features_remove
gst_caps_features_remove_id
<SUBSECTION Standard>
GST_CAPS_FEATURES
GST_CAPS_FEATURES_CAST
GST_IS_CAPS_FEATURES
GST_TYPE_CAPS_FEATURES
gst_is_caps_features
<SUBSECTION Private>
gst_caps_features_get_type
</SECTION>
<SECTION> <SECTION>
<FILE>gstsample</FILE> <FILE>gstsample</FILE>
<TITLE>GstSample</TITLE> <TITLE>GstSample</TITLE>
@ -3137,6 +3184,11 @@ GST_VALUE_HOLDS_CAPS
gst_value_set_caps gst_value_set_caps
gst_value_get_caps gst_value_get_caps
<SUBSECTION capsfeature>
GST_VALUE_HOLDS_CAPS_FEATURES
gst_value_set_caps_features
gst_value_get_caps_features
<SUBSECTION structure> <SUBSECTION structure>
GST_VALUE_HOLDS_STRUCTURE GST_VALUE_HOLDS_STRUCTURE
gst_value_set_structure gst_value_set_structure

View file

@ -55,6 +55,7 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
gstbufferpool.c \ gstbufferpool.c \
gstbus.c \ gstbus.c \
gstcaps.c \ gstcaps.c \
gstcapsfeatures.c \
gstchildproxy.c \ gstchildproxy.c \
gstclock.c \ gstclock.c \
gstcontext.c \ gstcontext.c \
@ -151,6 +152,7 @@ gst_headers = \
gstbufferpool.h \ gstbufferpool.h \
gstbus.h \ gstbus.h \
gstcaps.h \ gstcaps.h \
gstcapsfeatures.h \
gstchildproxy.h \ gstchildproxy.h \
gstclock.h \ gstclock.h \
gstcompat.h \ gstcompat.h \

View file

@ -562,6 +562,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
_priv_gst_query_initialize (); _priv_gst_query_initialize ();
_priv_gst_structure_initialize (); _priv_gst_structure_initialize ();
_priv_gst_caps_initialize (); _priv_gst_caps_initialize ();
_priv_gst_caps_features_initialize ();
_priv_gst_meta_initialize (); _priv_gst_meta_initialize ();
g_type_class_ref (gst_object_get_type ()); g_type_class_ref (gst_object_get_type ());

View file

@ -36,6 +36,7 @@
#include <gst/gstbufferlist.h> #include <gst/gstbufferlist.h>
#include <gst/gstbufferpool.h> #include <gst/gstbufferpool.h>
#include <gst/gstcaps.h> #include <gst/gstcaps.h>
#include <gst/gstcapsfeatures.h>
#include <gst/gstchildproxy.h> #include <gst/gstchildproxy.h>
#include <gst/gstclock.h> #include <gst/gstclock.h>
#include <gst/gstcontrolsource.h> #include <gst/gstcontrolsource.h>

View file

@ -105,6 +105,7 @@ G_GNUC_INTERNAL void _priv_gst_buffer_initialize (void);
G_GNUC_INTERNAL void _priv_gst_buffer_list_initialize (void); G_GNUC_INTERNAL void _priv_gst_buffer_list_initialize (void);
G_GNUC_INTERNAL void _priv_gst_structure_initialize (void); G_GNUC_INTERNAL void _priv_gst_structure_initialize (void);
G_GNUC_INTERNAL void _priv_gst_caps_initialize (void); G_GNUC_INTERNAL void _priv_gst_caps_initialize (void);
G_GNUC_INTERNAL void _priv_gst_caps_features_initialize (void);
G_GNUC_INTERNAL void _priv_gst_event_initialize (void); G_GNUC_INTERNAL void _priv_gst_event_initialize (void);
G_GNUC_INTERNAL void _priv_gst_format_initialize (void); G_GNUC_INTERNAL void _priv_gst_format_initialize (void);
G_GNUC_INTERNAL void _priv_gst_message_initialize (void); G_GNUC_INTERNAL void _priv_gst_message_initialize (void);
@ -132,10 +133,19 @@ G_GNUC_INTERNAL void _priv_gst_element_state_changed (GstElement *element,
/* used in both gststructure.c and gstcaps.c; numbers are completely made up */ /* used in both gststructure.c and gstcaps.c; numbers are completely made up */
#define STRUCTURE_ESTIMATED_STRING_LEN(s) (16 + gst_structure_n_fields(s) * 22) #define STRUCTURE_ESTIMATED_STRING_LEN(s) (16 + gst_structure_n_fields(s) * 22)
#define FEATURES_ESTIMATED_STRING_LEN(s) (16 + gst_caps_features_get_size(s) * 14)
G_GNUC_INTERNAL G_GNUC_INTERNAL
gboolean priv_gst_structure_append_to_gstring (const GstStructure * structure, gboolean priv_gst_structure_append_to_gstring (const GstStructure * structure,
GString * s); GString * s);
G_GNUC_INTERNAL
void priv_gst_caps_features_append_to_gstring (const GstCapsFeatures * features, GString *s);
G_GNUC_INTERNAL
gboolean priv_gst_structure_parse_name (gchar * str, gchar **start, gchar ** end, gchar ** next);
G_GNUC_INTERNAL
gboolean priv_gst_structure_parse_fields (gchar *str, gchar ** end, GstStructure *structure);
/* registry cache backends */ /* registry cache backends */
G_GNUC_INTERNAL G_GNUC_INTERNAL
gboolean priv_gst_registry_binary_read_cache (GstRegistry * registry, const char *location); gboolean priv_gst_registry_binary_read_cache (GstRegistry * registry, const char *location);

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@
#include <gst/gstconfig.h> #include <gst/gstconfig.h>
#include <gst/gstminiobject.h> #include <gst/gstminiobject.h>
#include <gst/gststructure.h> #include <gst/gststructure.h>
#include <gst/gstcapsfeatures.h>
#include <gst/glib-compat.h> #include <gst/glib-compat.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -384,16 +385,27 @@ void gst_caps_append (GstCaps *caps1,
GstCaps *caps2); GstCaps *caps2);
void gst_caps_append_structure (GstCaps *caps, void gst_caps_append_structure (GstCaps *caps,
GstStructure *structure); GstStructure *structure);
void gst_caps_append_structure_full (GstCaps *caps,
GstStructure *structure,
GstCapsFeatures *features);
void gst_caps_remove_structure (GstCaps *caps, guint idx); void gst_caps_remove_structure (GstCaps *caps, guint idx);
GstCaps * gst_caps_merge (GstCaps *caps1, GstCaps * gst_caps_merge (GstCaps *caps1,
GstCaps *caps2) G_GNUC_WARN_UNUSED_RESULT; GstCaps *caps2) G_GNUC_WARN_UNUSED_RESULT;
GstCaps * gst_caps_merge_structure (GstCaps *caps, GstCaps * gst_caps_merge_structure (GstCaps *caps,
GstStructure *structure) G_GNUC_WARN_UNUSED_RESULT; GstStructure *structure) G_GNUC_WARN_UNUSED_RESULT;
GstCaps * gst_caps_merge_structure_full (GstCaps *caps,
GstStructure *structure,
GstCapsFeatures *features) G_GNUC_WARN_UNUSED_RESULT;
guint gst_caps_get_size (const GstCaps *caps); guint gst_caps_get_size (const GstCaps *caps);
GstStructure * gst_caps_get_structure (const GstCaps *caps, GstStructure * gst_caps_get_structure (const GstCaps *caps,
guint index); guint index);
GstStructure * gst_caps_steal_structure (GstCaps *caps, GstStructure * gst_caps_steal_structure (GstCaps *caps,
guint index) G_GNUC_WARN_UNUSED_RESULT; guint index) G_GNUC_WARN_UNUSED_RESULT;
void gst_caps_set_features (GstCaps *caps,
guint index,
GstCapsFeatures * features);
GstCapsFeatures * gst_caps_get_features (const GstCaps *caps,
guint index);
GstCaps * gst_caps_copy_nth (const GstCaps *caps, guint nth) G_GNUC_WARN_UNUSED_RESULT; GstCaps * gst_caps_copy_nth (const GstCaps *caps, guint nth) G_GNUC_WARN_UNUSED_RESULT;
GstCaps * gst_caps_truncate (GstCaps *caps) G_GNUC_WARN_UNUSED_RESULT; GstCaps * gst_caps_truncate (GstCaps *caps) G_GNUC_WARN_UNUSED_RESULT;
void gst_caps_set_value (GstCaps *caps, void gst_caps_set_value (GstCaps *caps,
@ -415,6 +427,9 @@ gboolean gst_caps_is_subset (const GstCaps *subset,
const GstCaps *superset); const GstCaps *superset);
gboolean gst_caps_is_subset_structure (const GstCaps *caps, gboolean gst_caps_is_subset_structure (const GstCaps *caps,
const GstStructure *structure); const GstStructure *structure);
gboolean gst_caps_is_subset_structure_full (const GstCaps *caps,
const GstStructure *structure,
const GstCapsFeatures *features);
gboolean gst_caps_is_equal (const GstCaps *caps1, gboolean gst_caps_is_equal (const GstCaps *caps1,
const GstCaps *caps2); const GstCaps *caps2);
gboolean gst_caps_is_equal_fixed (const GstCaps *caps1, gboolean gst_caps_is_equal_fixed (const GstCaps *caps1,

740
gst/gstcapsfeatures.c Normal file
View file

@ -0,0 +1,740 @@
/* 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
* @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.
*
* 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".
*/
#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;
};
GType _gst_caps_features_type = 0;
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_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_memory_system_memory =
gst_caps_features_new_id (_gst_caps_feature_memory_system_memory, 0);
GST_DEBUG_CATEGORY_INIT (gst_caps_features_debug, "caps-features", 0,
"GstCapsFeatures debug");
}
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new, empty #GstCapsFeatures
*/
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));
GST_TRACE ("created caps features %p", features);
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new, empty #GstCapsFeatures
*/
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new, empty #GstCapsFeatures
*/
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new, empty #GstCapsFeatures
*/
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new, empty #GstCapsFeatures
*/
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 section of the design documents.
*
* Returns: %TRUE if the parent refcount could be set.
*/
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new #GstCapsFeatures.
*/
GstCapsFeatures *
gst_caps_features_copy (const GstCapsFeatures * features)
{
GstCapsFeatures *copy;
guint i, n;
g_return_val_if_fail (features != NULL, NULL);
g_return_val_if_fail (features->parent_refcount == 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));
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.
*/
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:
* |[
* GST_LOG ("features is %" GST_PTR_FORMAT, features);
* ]|
* This prints the features in human readble form.
*
* Free-function: g_free
*
* Returns: (transfer full): a pointer to string allocated by g_malloc().
* g_free() after usage.
*/
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);
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.
*
* Free-function: gst_caps_features_free
*
* Returns: (transfer full): a new #GstCapsFeatures or NULL when the string could
* not be parsed. Free with gst_caps_features_free() after use.
*/
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;
/* 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.
*/
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: The @i-th feature of @features.
*/
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.
*/
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
*
* Returns %TRUE if @features contains @feature.
*
* Returns: %TRUE if @features contains @feature.
*/
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
*
* Returns %TRUE if @features contains @feature.
*
* Returns: %TRUE if @features contains @feature.
*/
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);
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.
*
* Returns %TRUE if @features1 and @features2 are equal.
*
* Returns: %TRUE if @features1 and @features2 are equal.
*/
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);
/* 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_add:
* @features: a #GstCapsFeatures.
* @feature: a feature.
*
* Adds @feature to @features.
*/
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);
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.
*/
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);
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 explicitely if it is tried 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.
*/
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.
*/
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);
}

74
gst/gstcapsfeatures.h Normal file
View file

@ -0,0 +1,74 @@
/* 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.
*/
#ifndef __GST_CAPS_FEATURES_H__
#define __GST_CAPS_FEATURES_H__
#include <gst/gstconfig.h>
#include <gst/glib-compat.h>
G_BEGIN_DECLS
typedef struct _GstCapsFeatures GstCapsFeatures;
#define GST_TYPE_CAPS_FEATURES (gst_caps_features_get_type ())
#define GST_IS_CAPS_FEATURES(object) (gst_is_caps_features(object))
#define GST_CAPS_FEATURES_CAST(object) ((GstCapsFeatures *)(object))
#define GST_CAPS_FEATURES(object) (GST_CAPS_FEATURES_CAST(object))
#define GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY "memory:SystemMemory"
GST_EXPORT GstCapsFeatures *_gst_caps_features_memory_system_memory;
#define GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY (_gst_caps_features_memory_system_memory)
GType gst_caps_features_get_type (void);
gboolean gst_is_caps_features (gconstpointer obj);
GstCapsFeatures * gst_caps_features_new_empty (void);
GstCapsFeatures * gst_caps_features_new (const gchar *feature1, ...);
GstCapsFeatures * gst_caps_features_new_valist (const gchar *feature1, va_list varargs);
GstCapsFeatures * gst_caps_features_new_id (GQuark feature1, ...);
GstCapsFeatures * gst_caps_features_new_id_valist (GQuark feature1, va_list varargs);
gboolean gst_caps_features_set_parent_refcount (GstCapsFeatures *features, gint * refcount);
GstCapsFeatures * gst_caps_features_copy (const GstCapsFeatures * features);
void gst_caps_features_free (GstCapsFeatures * features);
gchar * gst_caps_features_to_string (const GstCapsFeatures * features);
GstCapsFeatures * gst_caps_features_from_string (const gchar * features);
guint gst_caps_features_get_size (const GstCapsFeatures * features);
const gchar * gst_caps_features_get_nth (const GstCapsFeatures * features, guint i);
GQuark gst_caps_features_get_nth_id (const GstCapsFeatures * features, guint i);
gboolean gst_caps_features_contains (const GstCapsFeatures * features, const gchar * feature);
gboolean gst_caps_features_contains_id (const GstCapsFeatures * features, GQuark feature);
gboolean gst_caps_features_is_equal (const GstCapsFeatures * features1, const GstCapsFeatures * features2);
void gst_caps_features_add (GstCapsFeatures * features, const gchar * feature);
void gst_caps_features_add_id ( GstCapsFeatures * features, GQuark feature);
void gst_caps_features_remove (GstCapsFeatures * features, const gchar * feature);
void gst_caps_features_remove_id (GstCapsFeatures * features, GQuark feature);
G_END_DECLS
#endif /* __GST_CAPS_FEATURES_H__ */

View file

@ -121,6 +121,7 @@
#include "gstquark.h" #include "gstquark.h"
#include "gstsegment.h" #include "gstsegment.h"
#include "gstvalue.h" #include "gstvalue.h"
#include "gstcapsfeatures.h"
#ifdef HAVE_VALGRIND_VALGRIND_H #ifdef HAVE_VALGRIND_VALGRIND_H
# include <valgrind/valgrind.h> # include <valgrind/valgrind.h>
@ -628,6 +629,9 @@ gst_debug_print_object (gpointer ptr)
if (*(GType *) ptr == GST_TYPE_STRUCTURE) { if (*(GType *) ptr == GST_TYPE_STRUCTURE) {
return gst_info_structure_to_string ((const GstStructure *) ptr); return gst_info_structure_to_string ((const GstStructure *) ptr);
} }
if (*(GType *) ptr == GST_TYPE_STRUCTURE) {
return gst_caps_features_to_string ((const GstCapsFeatures *) ptr);
}
if (*(GType *) ptr == GST_TYPE_TAG_LIST) { if (*(GType *) ptr == GST_TYPE_TAG_LIST) {
/* FIXME: want pretty tag list with long byte dumps removed.. */ /* FIXME: want pretty tag list with long byte dumps removed.. */
return gst_tag_list_to_string ((GstTagList *) ptr); return gst_tag_list_to_string ((GstTagList *) ptr);

View file

@ -326,7 +326,7 @@ gst_structure_set_parent_refcount (GstStructure * structure, gint * refcount)
* *
* Free-function: gst_structure_free * Free-function: gst_structure_free
* *
* Returns: (transfer none): a new #GstStructure. * Returns: (transfer full): a new #GstStructure.
*/ */
GstStructure * GstStructure *
gst_structure_copy (const GstStructure * structure) gst_structure_copy (const GstStructure * structure)
@ -1781,7 +1781,6 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
g_return_val_if_fail (s != NULL, FALSE); g_return_val_if_fail (s != NULL, FALSE);
g_string_append (s, g_quark_to_string (structure->name));
len = GST_STRUCTURE_FIELDS (structure)->len; len = GST_STRUCTURE_FIELDS (structure)->len;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
char *t; char *t;
@ -1839,6 +1838,7 @@ gst_structure_to_string (const GstStructure * structure)
/* we estimate a minimum size based on the number of fields in order to /* we estimate a minimum size based on the number of fields in order to
* avoid unnecessary reallocs within GString */ * avoid unnecessary reallocs within GString */
s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure)); s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure));
g_string_append (s, g_quark_to_string (structure->name));
priv_gst_structure_append_to_gstring (structure, s); priv_gst_structure_append_to_gstring (structure, s);
return g_string_free (s, FALSE); return g_string_free (s, FALSE);
} }
@ -2236,6 +2236,77 @@ gst_structure_parse_value (gchar * str,
return ret; return ret;
} }
gboolean
priv_gst_structure_parse_name (gchar * str, gchar ** start, gchar ** end,
gchar ** next)
{
char *w;
char *r;
r = str;
/* skip spaces (FIXME: _isspace treats tabs and newlines as space!) */
while (*r && (g_ascii_isspace (*r) || (r[0] == '\\'
&& g_ascii_isspace (r[1]))))
r++;
*start = r;
if (G_UNLIKELY (!gst_structure_parse_string (r, &w, &r, TRUE))) {
GST_WARNING ("Failed to parse structure string '%s'", str);
return FALSE;
}
*end = w;
*next = r;
return TRUE;
}
gboolean
priv_gst_structure_parse_fields (gchar * str, gchar ** end,
GstStructure * structure)
{
gchar *r;
GstStructureField field;
r = str;
do {
while (*r && (g_ascii_isspace (*r) || (r[0] == '\\'
&& g_ascii_isspace (r[1]))))
r++;
if (*r == ';') {
/* end of structure, get the next char and finish */
r++;
break;
}
if (*r == '\0') {
/* accept \0 as end delimiter */
break;
}
if (G_UNLIKELY (*r != ',')) {
GST_WARNING ("Failed to find delimiter, r=%s", r);
return FALSE;
}
r++;
while (*r && (g_ascii_isspace (*r) || (r[0] == '\\'
&& g_ascii_isspace (r[1]))))
r++;
memset (&field, 0, sizeof (field));
if (G_UNLIKELY (!gst_structure_parse_field (r, &r, &field))) {
GST_WARNING ("Failed to parse field, r=%s", r);
return FALSE;
}
gst_structure_set_field (structure, &field);
} while (TRUE);
*end = r;
return TRUE;
}
/** /**
* gst_structure_from_string: * gst_structure_from_string:
* @string: a string representation of a #GstStructure. * @string: a string representation of a #GstStructure.
@ -2259,23 +2330,14 @@ gst_structure_from_string (const gchar * string, gchar ** end)
char *r; char *r;
char save; char save;
GstStructure *structure = NULL; GstStructure *structure = NULL;
GstStructureField field;
g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (string != NULL, NULL);
copy = g_strdup (string); copy = g_strdup (string);
r = copy; r = copy;
/* skip spaces (FIXME: _isspace treats tabs and newlines as space!) */ if (!priv_gst_structure_parse_name (r, &name, &w, &r))
while (*r && (g_ascii_isspace (*r) || (r[0] == '\\'
&& g_ascii_isspace (r[1]))))
r++;
name = r;
if (G_UNLIKELY (!gst_structure_parse_string (r, &w, &r, TRUE))) {
GST_WARNING ("Failed to parse structure string '%s'", string);
goto error; goto error;
}
save = *w; save = *w;
*w = '\0'; *w = '\0';
@ -2285,35 +2347,8 @@ gst_structure_from_string (const gchar * string, gchar ** end)
if (G_UNLIKELY (structure == NULL)) if (G_UNLIKELY (structure == NULL))
goto error; goto error;
do { if (!priv_gst_structure_parse_fields (r, &r, structure))
while (*r && (g_ascii_isspace (*r) || (r[0] == '\\' goto error;
&& g_ascii_isspace (r[1]))))
r++;
if (*r == ';') {
/* end of structure, get the next char and finish */
r++;
break;
}
if (*r == '\0') {
/* accept \0 as end delimiter */
break;
}
if (G_UNLIKELY (*r != ',')) {
GST_WARNING ("Failed to find delimiter, r=%s", r);
goto error;
}
r++;
while (*r && (g_ascii_isspace (*r) || (r[0] == '\\'
&& g_ascii_isspace (r[1]))))
r++;
memset (&field, 0, sizeof (field));
if (G_UNLIKELY (!gst_structure_parse_field (r, &r, &field))) {
GST_WARNING ("Failed to parse field, r=%s", r);
goto error;
}
gst_structure_set_field (structure, &field);
} while (TRUE);
if (end) if (end)
*end = (char *) string + (r - copy); *end = (char *) string + (r - copy);

View file

@ -1996,6 +1996,76 @@ gst_value_deserialize_structure (GValue * dest, const gchar * s)
return FALSE; return FALSE;
} }
/*******************
* GstCapsFeatures *
*******************/
/**
* gst_value_set_caps_features:
* @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
* @features: the features to set the value to
*
* Sets the contents of @value to @features.
*/
void
gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
{
g_return_if_fail (G_IS_VALUE (value));
g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
g_value_set_boxed (value, features);
}
/**
* gst_value_get_caps_features:
* @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
*
* Gets the contents of @value.
*
* Returns: (transfer none): the contents of @value
*/
const GstCapsFeatures *
gst_value_get_caps_features (const GValue * value)
{
g_return_val_if_fail (G_IS_VALUE (value), NULL);
g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
return (GstCapsFeatures *) g_value_get_boxed (value);
}
static gchar *
gst_value_serialize_caps_features (const GValue * value)
{
GstCapsFeatures *features = g_value_get_boxed (value);
return gst_string_take_and_wrap (gst_caps_features_to_string (features));
}
static gboolean
gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
{
GstCapsFeatures *features;
if (*s != '"') {
features = gst_caps_features_from_string (s);
} else {
gchar *str = gst_string_unwrap (s);
if (G_UNLIKELY (!str))
return FALSE;
features = gst_caps_features_from_string (str);
g_free (str);
}
if (G_LIKELY (features)) {
g_value_take_boxed (dest, features);
return TRUE;
}
return FALSE;
}
/************** /**************
* GstTagList * * GstTagList *
**************/ **************/
@ -6002,6 +6072,17 @@ _priv_gst_value_initialize (void)
gst_value.type = GST_TYPE_STRUCTURE; gst_value.type = GST_TYPE_STRUCTURE;
gst_value_register (&gst_value); gst_value_register (&gst_value);
} }
{
static GstValueTable gst_value = {
0,
NULL,
gst_value_serialize_caps_features,
gst_value_deserialize_caps_features,
};
gst_value.type = GST_TYPE_CAPS_FEATURES;
gst_value_register (&gst_value);
}
{ {
static GstValueTable gst_value = { static GstValueTable gst_value = {
0, 0,

View file

@ -23,6 +23,7 @@
#include <gst/gstconfig.h> #include <gst/gstconfig.h>
#include <gst/gstcaps.h> #include <gst/gstcaps.h>
#include <gst/gststructure.h> #include <gst/gststructure.h>
#include <gst/gstcapsfeatures.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -149,6 +150,14 @@ G_BEGIN_DECLS
*/ */
#define GST_VALUE_HOLDS_STRUCTURE(x) (G_VALUE_HOLDS((x), GST_TYPE_STRUCTURE)) #define GST_VALUE_HOLDS_STRUCTURE(x) (G_VALUE_HOLDS((x), GST_TYPE_STRUCTURE))
/**
* GST_VALUE_HOLDS_CAPS_FEATURES:
* @x: the #GValue to check
*
* Checks if the given #GValue contains a #GST_TYPE_CAPS_FEATURES value.
*/
#define GST_VALUE_HOLDS_CAPS_FEATURES(x) (G_VALUE_HOLDS((x), GST_TYPE_CAPS_FEATURES))
/** /**
* GST_VALUE_HOLDS_BUFFER: * GST_VALUE_HOLDS_BUFFER:
* @x: the #GValue to check * @x: the #GValue to check
@ -472,6 +481,12 @@ const GstStructure *
void gst_value_set_structure (GValue *value, void gst_value_set_structure (GValue *value,
const GstStructure *structure); const GstStructure *structure);
/* caps features */
const GstCapsFeatures *
gst_value_get_caps_features (const GValue *value);
void gst_value_set_caps_features (GValue *value,
const GstCapsFeatures *features);
/* fraction */ /* fraction */
void gst_value_set_fraction (GValue *value, void gst_value_set_fraction (GValue *value,
gint numerator, gint numerator,

View file

@ -106,6 +106,7 @@ check_PROGRAMS = \
gst/gstmemory \ gst/gstmemory \
gst/gstbus \ gst/gstbus \
gst/gstcaps \ gst/gstcaps \
gst/gstcapsfeatures \
$(CXX_CHECKS) \ $(CXX_CHECKS) \
gst/gstdatetime \ gst/gstdatetime \
gst/gstinfo \ gst/gstinfo \

View file

@ -982,6 +982,93 @@ GST_START_TEST (test_broken)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_features)
{
GstCaps *c1, *c2, *c3;
GstStructure *s1, *s2;
GstCapsFeatures *f1, *f2;
gchar *str1;
static GstStaticCaps scaps =
GST_STATIC_CAPS
("video/x-raw(memory:EGLImage), width=320, height=[ 240, 260 ]");
c1 = gst_caps_new_empty ();
fail_unless (c1 != NULL);
s1 = gst_structure_new ("video/x-raw", "width", G_TYPE_INT, 320, "height",
GST_TYPE_INT_RANGE, 240, 260, NULL);
fail_unless (s1 != NULL);
f1 = gst_caps_features_new ("memory:EGLImage", NULL);
fail_unless (f1 != NULL);
gst_caps_append_structure_full (c1, s1, f1);
s2 = gst_caps_get_structure (c1, 0);
fail_unless (s1 == s2);
f2 = gst_caps_get_features (c1, 0);
fail_unless (f1 == f2);
str1 = gst_caps_to_string (c1);
fail_unless (str1 != NULL);
c2 = gst_caps_from_string (str1);
fail_unless (c2 != NULL);
g_free (str1);
fail_unless (gst_caps_is_equal (c1, c2));
fail_unless (gst_caps_is_subset (c1, c2));
fail_unless (gst_caps_is_subset (c2, c1));
fail_unless (gst_caps_can_intersect (c1, c2));
gst_caps_unref (c2);
c2 = gst_caps_new_empty ();
fail_unless (c2 != NULL);
s2 = gst_structure_new ("video/x-raw", "width", G_TYPE_INT, 320, "height",
GST_TYPE_INT_RANGE, 240, 260, NULL);
fail_unless (s2 != NULL);
f2 = gst_caps_features_new ("memory:VASurface", "meta:VAMeta", NULL);
fail_unless (f2 != NULL);
gst_caps_append_structure_full (c2, s2, f2);
fail_if (gst_caps_is_equal (c1, c2));
fail_if (gst_caps_is_subset (c1, c2));
fail_if (gst_caps_is_subset (c2, c1));
fail_if (gst_caps_can_intersect (c1, c2));
str1 = gst_caps_to_string (c2);
fail_unless (str1 != NULL);
c3 = gst_caps_from_string (str1);
fail_unless (c3 != NULL);
g_free (str1);
fail_unless (gst_caps_is_equal (c2, c3));
fail_unless (gst_caps_is_subset (c2, c3));
fail_unless (gst_caps_is_subset (c3, c2));
fail_unless (gst_caps_can_intersect (c2, c3));
f1 = gst_caps_get_features (c3, 0);
fail_unless (f1 != NULL);
fail_if (f1 == f2);
gst_caps_features_contains (f1, "memory:VASurface");
gst_caps_features_remove (f1, "memory:VASurface");
fail_if (gst_caps_is_equal (c2, c3));
fail_if (gst_caps_is_subset (c2, c3));
fail_if (gst_caps_is_subset (c3, c2));
fail_if (gst_caps_can_intersect (c2, c3));
gst_caps_unref (c3);
gst_caps_unref (c2);
c2 = gst_static_caps_get (&scaps);
fail_unless (c2 != NULL);
fail_unless (gst_caps_is_equal (c1, c2));
fail_unless (gst_caps_is_subset (c1, c2));
fail_unless (gst_caps_is_subset (c2, c1));
fail_unless (gst_caps_can_intersect (c1, c2));
gst_caps_unref (c1);
gst_caps_unref (c2);
}
GST_END_TEST;
static Suite * static Suite *
gst_caps_suite (void) gst_caps_suite (void)
@ -1009,6 +1096,7 @@ gst_caps_suite (void)
tcase_add_test (tc_chain, test_intersect_duplication); tcase_add_test (tc_chain, test_intersect_duplication);
tcase_add_test (tc_chain, test_normalize); tcase_add_test (tc_chain, test_normalize);
tcase_add_test (tc_chain, test_broken); tcase_add_test (tc_chain, test_broken);
tcase_add_test (tc_chain, test_features);
return s; return s;
} }

View file

@ -0,0 +1,97 @@
/* GStreamer
* Copyright (C) 2013 Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* gstcapsfeatures.c: Unit test for GstCapsFeatures
*
* 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.
*/
#include <gst/check/gstcheck.h>
#include <gst/gstcapsfeatures.h>
GST_START_TEST (test_basic_operations)
{
GstCapsFeatures *a, *b;
a = gst_caps_features_new ("m:abc", "m:def", "m:ghi", NULL);
fail_unless (a != NULL);
b = gst_caps_features_copy (a);
fail_unless (b != NULL);
fail_unless (gst_caps_features_is_equal (a, b));
fail_if (gst_caps_features_is_equal (a,
GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY));
fail_unless_equals_int (gst_caps_features_get_size (a), 3);
fail_unless_equals_string (gst_caps_features_get_nth (a, 1), "m:def");
gst_caps_features_add (b, "m:jkl");
fail_if (gst_caps_features_is_equal (a, b));
fail_unless_equals_int (gst_caps_features_get_size (b), 4);
fail_unless_equals_string (gst_caps_features_get_nth (b, 3), "m:jkl");
gst_caps_features_add (b, "m:jkl");
fail_unless_equals_int (gst_caps_features_get_size (b), 4);
gst_caps_features_remove (b, "m:jkl");
fail_unless (gst_caps_features_is_equal (a, b));
gst_caps_features_remove (b, "m:abc");
gst_caps_features_add (b, "m:abc");
fail_unless (gst_caps_features_is_equal (a, b));
gst_caps_features_remove (b, "m:abc");
gst_caps_features_remove (b, "m:def");
gst_caps_features_remove (b, "m:ghi");
fail_unless (gst_caps_features_is_equal (b,
GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY));
gst_caps_features_add (b, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
gst_caps_features_free (a);
gst_caps_features_free (b);
}
GST_END_TEST;
GST_START_TEST (test_from_to_string)
{
GstCapsFeatures *a, *b;
gchar *str;
a = gst_caps_features_new ("m:abc", "m:def", "m:ghi", NULL);
fail_unless (a != NULL);
str = gst_caps_features_to_string (a);
fail_unless (str != NULL);
fail_unless_equals_string (str, "m:abc, m:def, m:ghi");
b = gst_caps_features_from_string (str);
fail_unless (b != NULL);
fail_unless (gst_caps_features_is_equal (a, b));
gst_caps_features_free (a);
gst_caps_features_free (b);
g_free (str);
}
GST_END_TEST;
static Suite *
gst_capsfeatures_suite (void)
{
Suite *s = suite_create ("GstCapsFeatures");
TCase *tc_chain = tcase_create ("operations");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_basic_operations);
tcase_add_test (tc_chain, test_from_to_string);
return s;
}
GST_CHECK_MAIN (gst_capsfeatures);

View file

@ -34,6 +34,8 @@ EXPORTS
_gst_buffer_list_type DATA _gst_buffer_list_type DATA
_gst_buffer_type DATA _gst_buffer_type DATA
_gst_caps_any DATA _gst_caps_any DATA
_gst_caps_features_memory_system_memory DATA
_gst_caps_features_type DATA
_gst_caps_none DATA _gst_caps_none DATA
_gst_caps_type DATA _gst_caps_type DATA
_gst_debug_category_new _gst_debug_category_new
@ -190,11 +192,34 @@ EXPORTS
gst_bus_timed_pop_filtered gst_bus_timed_pop_filtered
gst_caps_append gst_caps_append
gst_caps_append_structure gst_caps_append_structure
gst_caps_append_structure_full
gst_caps_can_intersect gst_caps_can_intersect
gst_caps_copy_nth gst_caps_copy_nth
gst_caps_features_add
gst_caps_features_add_id
gst_caps_features_contains
gst_caps_features_contains_id
gst_caps_features_copy
gst_caps_features_free
gst_caps_features_from_string
gst_caps_features_get_nth
gst_caps_features_get_nth_id
gst_caps_features_get_size
gst_caps_features_get_type
gst_caps_features_is_equal
gst_caps_features_new
gst_caps_features_new_empty
gst_caps_features_new_id
gst_caps_features_new_id_valist
gst_caps_features_new_valist
gst_caps_features_remove
gst_caps_features_remove_id
gst_caps_features_set_parent_refcount
gst_caps_features_to_string
gst_caps_fixate gst_caps_fixate
gst_caps_flags_get_type gst_caps_flags_get_type
gst_caps_from_string gst_caps_from_string
gst_caps_get_features
gst_caps_get_size gst_caps_get_size
gst_caps_get_structure gst_caps_get_structure
gst_caps_get_type gst_caps_get_type
@ -210,8 +235,10 @@ EXPORTS
gst_caps_is_strictly_equal gst_caps_is_strictly_equal
gst_caps_is_subset gst_caps_is_subset
gst_caps_is_subset_structure gst_caps_is_subset_structure
gst_caps_is_subset_structure_full
gst_caps_merge gst_caps_merge
gst_caps_merge_structure gst_caps_merge_structure
gst_caps_merge_structure_full
gst_caps_new_any gst_caps_new_any
gst_caps_new_empty gst_caps_new_empty
gst_caps_new_empty_simple gst_caps_new_empty_simple
@ -220,6 +247,7 @@ EXPORTS
gst_caps_new_simple gst_caps_new_simple
gst_caps_normalize gst_caps_normalize
gst_caps_remove_structure gst_caps_remove_structure
gst_caps_set_features
gst_caps_set_simple gst_caps_set_simple
gst_caps_set_simple_valist gst_caps_set_simple_valist
gst_caps_set_value gst_caps_set_value
@ -516,6 +544,7 @@ EXPORTS
gst_init_get_option_group gst_init_get_option_group
gst_int64_range_get_type gst_int64_range_get_type
gst_int_range_get_type gst_int_range_get_type
gst_is_caps_features
gst_is_initialized gst_is_initialized
gst_iterator_copy gst_iterator_copy
gst_iterator_filter gst_iterator_filter
@ -1277,6 +1306,7 @@ EXPORTS
gst_value_fraction_subtract gst_value_fraction_subtract
gst_value_get_bitmask gst_value_get_bitmask
gst_value_get_caps gst_value_get_caps
gst_value_get_caps_features
gst_value_get_double_range_max gst_value_get_double_range_max
gst_value_get_double_range_min gst_value_get_double_range_min
gst_value_get_fraction_denominator gst_value_get_fraction_denominator
@ -1305,6 +1335,7 @@ EXPORTS
gst_value_serialize gst_value_serialize
gst_value_set_bitmask gst_value_set_bitmask
gst_value_set_caps gst_value_set_caps
gst_value_set_caps_features
gst_value_set_double_range gst_value_set_double_range
gst_value_set_fraction gst_value_set_fraction
gst_value_set_fraction_range gst_value_set_fraction_range