implement caps merging (fixes #352580)

Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gstcaps.c: (gst_caps_structure_is_subset_field),
(gst_caps_structure_is_subset), (gst_caps_merge),
(gst_caps_merge_structure):
* gst/gstcaps.h:
* libs/gst/base/gstbasetransform.c:
(gst_base_transform_transform_caps):
* tests/check/gst/gstcaps.c: (GST_START_TEST), (gst_caps_suite):
implement caps merging (fixes #352580)
This commit is contained in:
Stefan Kost 2006-08-24 10:40:31 +00:00
parent 7c84afffac
commit fc8d184bba
6 changed files with 249 additions and 14 deletions

View file

@ -1,3 +1,15 @@
2006-08-24 Stefan Kost <ensonic@users.sf.net>
* docs/gst/gstreamer-sections.txt:
* gst/gstcaps.c: (gst_caps_structure_is_subset_field),
(gst_caps_structure_is_subset), (gst_caps_merge),
(gst_caps_merge_structure):
* gst/gstcaps.h:
* libs/gst/base/gstbasetransform.c:
(gst_base_transform_transform_caps):
* tests/check/gst/gstcaps.c: (GST_START_TEST), (gst_caps_suite):
implement caps merging (fixes #352580)
2006-08-23 Stefan Kost <ensonic@users.sf.net>
* tools/Makefile.am:

View file

@ -223,6 +223,7 @@ gst_caps_append
gst_caps_merge
gst_caps_append_structure
gst_caps_remove_structure
gst_caps_merge_structure
gst_caps_get_size
gst_caps_get_structure
gst_caps_set_simple

View file

@ -480,6 +480,75 @@ gst_structure_is_equal_foreach (GQuark field_id, const GValue * val2,
return FALSE;
}
static gboolean
gst_caps_structure_is_subset_field (GQuark field_id, const GValue * value,
gpointer user_data)
{
GstStructure *subtract_from = user_data;
GValue subtraction = { 0, };
const GValue *other;
gint res;
other = gst_structure_id_get_value (subtract_from, field_id);
if (!other) {
/* field is missing in one set */
return FALSE;
}
/*{
gchar *str = g_strdup_value_contents (value);
GST_DEBUG (" value: '%s'", str);
g_free (str);
str = g_strdup_value_contents (other);
GST_DEBUG (" other: '%s'", str);
g_free (str);
} */
/*
[1,2] - 1 = 2
1 - [1,2] = <EFBFBD> ???
*/
if (!gst_value_subtract (&subtraction, other, value)) {
/* empty result -> values are the same, or first was a value and
* second was a list
*/
/* verify that result is empty by swapping args */
if (!gst_value_subtract (&subtraction, value, other)) {
/*GST_DEBUG (" values are the same"); */
return TRUE;
}
g_value_unset (&subtraction);
return FALSE;
}
/*{
gchar *str = g_strdup_value_contents (&subtraction);
GST_DEBUG (" diff: '%s'", str);
g_free (str);
} */
res = gst_value_compare (&subtraction, other);
if (res == GST_VALUE_EQUAL) {
/* value was empty ? */
g_value_unset (&subtraction);
/*GST_DEBUG (" compare = equal (%d)",res); */
return FALSE;
} else {
/*GST_DEBUG (" compare = unequal/unordered (%d)",res); */
return TRUE;
}
}
static gboolean
gst_caps_structure_is_subset (const GstStructure * minuend,
const GstStructure * subtrahend)
{
if ((minuend->name != subtrahend->name) ||
(gst_structure_n_fields (minuend) !=
gst_structure_n_fields (subtrahend))) {
return FALSE;
}
return gst_structure_foreach ((GstStructure *) subtrahend,
gst_caps_structure_is_subset_field, (gpointer) minuend);
}
/**
* gst_caps_append:
* @caps1: the #GstCaps that will be appended to
@ -526,9 +595,9 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
* @caps1: the #GstCaps that will take the new entries
* @caps2: the #GstCaps to merge in
*
* Appends the structures contained in @caps2 to @caps1 if they are not yet in
* @caps1. The structures in @caps2 are not copied -- they are transferred to
* @caps1, and then @caps2 is freed.
* Appends the structures contained in @caps2 to @caps1 if they are not yet
* expressed by @caps1. The structures in @caps2 are not copied -- they are
* transferred to @caps1, and then @caps2 is freed.
* If either caps is ANY, the resulting caps will be ANY.
*/
void
@ -545,23 +614,33 @@ gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
#ifdef USE_POISONING
CAPS_POISON (caps2);
#endif
if (gst_caps_is_any (caps1) || gst_caps_is_any (caps2)) {
/* FIXME: this leaks */
caps1->flags |= GST_CAPS_FLAGS_ANY;
if (gst_caps_is_any (caps1)) {
for (i = caps2->structs->len - 1; i >= 0; i--) {
structure = gst_caps_remove_and_get_structure (caps2, i);
gst_structure_free (structure);
}
} else if (gst_caps_is_any (caps2)) {
caps1->flags |= GST_CAPS_FLAGS_ANY;
for (i = caps1->structs->len - 1; i >= 0; i--) {
structure = gst_caps_remove_and_get_structure (caps1, i);
gst_structure_free (structure);
}
} else {
int len = caps2->structs->len;
for (i = 0; i < len; i++) {
structure = gst_caps_remove_and_get_structure (caps2, 0);
gst_caps_merge_structure (caps1, structure);
}
/* this is too naive
GstCaps *com = gst_caps_intersect (caps1, caps2);
GstCaps *add = gst_caps_subtract (caps2, com);
/*
GST_DEBUG ("common : %d", gst_caps_get_size (com));
GST_DEBUG ("adding : %d", gst_caps_get_size (add));
*/
gst_caps_append (caps1, add);
gst_caps_unref (com);
*/
}
gst_caps_unref (caps2); /* guaranteed to free it */
}
@ -613,6 +692,54 @@ gst_caps_remove_structure (GstCaps * caps, guint idx)
gst_structure_free (structure);
}
/**
* gst_caps_merge_structure:
* @caps: the #GstCaps that will the the new structure
* @structure: the #GstStructure to merge
*
* Appends @structure to @caps if its not already expressed by @caps. The
* structure is not copied; @caps becomes the owner of @structure.
*/
void
gst_caps_merge_structure (GstCaps * caps, GstStructure * structure2)
{
g_return_if_fail (GST_IS_CAPS (caps));
g_return_if_fail (IS_WRITABLE (caps));
if (G_LIKELY (structure2)) {
GstStructure *structure1;
int i;
gboolean unique = TRUE;
g_return_if_fail (structure2->parent_refcount == NULL);
#if 0
#ifdef USE_POISONING
STRUCTURE_POISON (structure2);
#endif
#endif
/*GST_DEBUG ("merge ?: %" GST_PTR_FORMAT, structure2); */
/* check each structure */
for (i = caps->structs->len - 1; i >= 0; i--) {
structure1 = gst_caps_get_structure (caps, i);
/*GST_DEBUG (" with: %" GST_PTR_FORMAT, structure1); */
/* if structure2 is a subset of structure1, then skip it */
if (gst_caps_structure_is_subset (structure1, structure2)) {
/*GST_DEBUG (" no"); */
unique = FALSE;
break;
}
}
if (unique) {
/*GST_DEBUG (" yes"); */
gst_structure_set_parent_refcount (structure2, &caps->refcount);
g_ptr_array_add (caps->structs, structure2);
} else {
gst_structure_free (structure2);
}
}
}
/**
* gst_caps_get_size:
* @caps: a #GstCaps

View file

@ -199,6 +199,8 @@ void gst_caps_merge (GstCaps *caps1,
void gst_caps_append_structure (GstCaps *caps,
GstStructure *structure);
void gst_caps_remove_structure (GstCaps * caps, guint idx);
void gst_caps_merge_structure (GstCaps * caps1,
GstStructure * structure2);
guint gst_caps_get_size (const GstCaps *caps);
GstStructure * gst_caps_get_structure (const GstCaps *caps,
guint index);

View file

@ -453,10 +453,11 @@ gst_base_transform_transform_caps (GstBaseTransform * trans,
gst_caps_unref (nth);
GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
/* FIXME: here we need to only append those structures, that are not yet
* in there */
temp = gst_caps_make_writable (temp);
/*gst_caps_append (ret, temp); */
/* FIXME: here we need to only append those structures, that are not yet
* in there
* gst_caps_append (ret, temp);
*/
gst_caps_merge (ret, temp);
}
GST_DEBUG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));

View file

@ -348,6 +348,95 @@ GST_START_TEST (test_truncate)
GST_END_TEST;
GST_START_TEST (test_merge_fundamental)
{
GstCaps *c1, *c2;
/* ANY + specific = ANY */
c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
c2 = gst_caps_new_any ();
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 0, NULL);
fail_unless (gst_caps_is_any (c2), NULL);
gst_caps_unref (c2);
/* specific + ANY = ANY */
c2 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
c1 = gst_caps_new_any ();
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 0, NULL);
fail_unless (gst_caps_is_any (c2), NULL);
gst_caps_unref (c2);
/* EMPTY + specific = specific */
c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
c2 = gst_caps_new_empty ();
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 1, NULL);
fail_if (gst_caps_is_empty (c2), NULL);
gst_caps_unref (c2);
/* specific + EMPTY = specific */
c2 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
c1 = gst_caps_new_empty ();
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 1, NULL);
fail_if (gst_caps_is_empty (c2), NULL);
gst_caps_unref (c2);
}
GST_END_TEST;
GST_START_TEST (test_merge_same)
{
GstCaps *c1, *c2;
/* this is the same */
c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100,channels=1");
c2 = gst_caps_from_string ("audio/x-raw-int,rate=44100,channels=1");
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 1, NULL);
/* and so is this */
c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100,channels=1");
c2 = gst_caps_from_string ("audio/x-raw-int,channels=1,rate=44100");
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 1, NULL);
gst_caps_unref (c2);
}
GST_END_TEST;
GST_START_TEST (test_merge_subset)
{
GstCaps *c1, *c2;
/* the 2nd is already covered */
c2 = gst_caps_from_string ("audio/x-raw-int,channels=[1,2]");
c1 = gst_caps_from_string ("audio/x-raw-int,channels=1");
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 1, NULL);
/* here it is not */
c2 = gst_caps_from_string ("audio/x-raw-int,channels=1,rate=44100");
c1 = gst_caps_from_string ("audio/x-raw-int,channels=[1,2],rate=44100");
gst_caps_merge (c2, c1);
GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
fail_unless (gst_caps_get_size (c2) == 2, NULL);
gst_caps_unref (c2);
}
GST_END_TEST;
Suite *
gst_caps_suite (void)
@ -363,6 +452,9 @@ gst_caps_suite (void)
tcase_add_test (tc_chain, test_static_caps);
tcase_add_test (tc_chain, test_simplify);
tcase_add_test (tc_chain, test_truncate);
tcase_add_test (tc_chain, test_merge_fundamental);
tcase_add_test (tc_chain, test_merge_same);
tcase_add_test (tc_chain, test_merge_subset);
return s;
}