1 /* GStreamer 2 * Copyright (C) <2003> David A. Schleef <ds@schleef.org> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 /** 21 * SECTION:gstvalue 22 * @short_description: GValue implementations specific 23 * to GStreamer 24 * 25 * GValue implementations specific to GStreamer. 26 * 27 * Note that operations on the same #GValue from multiple threads may lead to 28 * undefined behaviour. 29 */ 30 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 #include <math.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <ctype.h> 39 40 #include "gst_private.h" 41 #include "glib-compat-private.h" 42 #include <gst/gst.h> 43 #include <gobject/gvaluecollector.h> 44 #include "gstutils.h" 45 46 /* GstValueUnionFunc: 47 * @dest: a #GValue for the result 48 * @value1: a #GValue operand 49 * @value2: a #GValue operand 50 * 51 * Used by gst_value_union() to perform unification for a specific #GValue 52 * type. Register a new implementation with gst_value_register_union_func(). 53 * 54 * Returns: %TRUE if a union was successful 55 */ 56 typedef gboolean (*GstValueUnionFunc) (GValue * dest, 57 const GValue * value1, const GValue * value2); 58 59 /* GstValueIntersectFunc: 60 * @dest: (out caller-allocates): a #GValue for the result 61 * @value1: a #GValue operand 62 * @value2: a #GValue operand 63 * 64 * Used by gst_value_intersect() to perform intersection for a specific #GValue 65 * type. If the intersection is non-empty, the result is 66 * placed in @dest and %TRUE is returned. If the intersection is 67 * empty, @dest is unmodified and %FALSE is returned. 68 * Register a new implementation with gst_value_register_intersect_func(). 69 * 70 * Returns: %TRUE if the values can intersect 71 */ 72 typedef gboolean (*GstValueIntersectFunc) (GValue * dest, 73 const GValue * value1, const GValue * value2); 74 75 /* GstValueSubtractFunc: 76 * @dest: (out caller-allocates): a #GValue for the result 77 * @minuend: a #GValue operand 78 * @subtrahend: a #GValue operand 79 * 80 * Used by gst_value_subtract() to perform subtraction for a specific #GValue 81 * type. Register a new implementation with gst_value_register_subtract_func(). 82 * 83 * Returns: %TRUE if the subtraction is not empty 84 */ 85 typedef gboolean (*GstValueSubtractFunc) (GValue * dest, 86 const GValue * minuend, const GValue * subtrahend); 87 88 static void gst_value_register_union_func (GType type1, 89 GType type2, GstValueUnionFunc func); 90 static void gst_value_register_intersect_func (GType type1, 91 GType type2, GstValueIntersectFunc func); 92 static void gst_value_register_subtract_func (GType minuend_type, 93 GType subtrahend_type, GstValueSubtractFunc func); 94 95 typedef struct _GstValueUnionInfo GstValueUnionInfo; 96 struct _GstValueUnionInfo 97 { 98 GType type1; 99 GType type2; 100 GstValueUnionFunc func; 101 }; 102 103 typedef struct _GstValueIntersectInfo GstValueIntersectInfo; 104 struct _GstValueIntersectInfo 105 { 106 GType type1; 107 GType type2; 108 GstValueIntersectFunc func; 109 }; 110 111 typedef struct _GstValueSubtractInfo GstValueSubtractInfo; 112 struct _GstValueSubtractInfo 113 { 114 GType minuend; 115 GType subtrahend; 116 GstValueSubtractFunc func; 117 }; 118 119 #define FUNDAMENTAL_TYPE_ID_MAX \ 120 (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) 121 #define FUNDAMENTAL_TYPE_ID(type) \ 122 ((type) >> G_TYPE_FUNDAMENTAL_SHIFT) 123 124 #define VALUE_LIST_ARRAY(v) ((GArray *) (v)->data[0].v_pointer) 125 #define VALUE_LIST_SIZE(v) (VALUE_LIST_ARRAY(v)->len) 126 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index (VALUE_LIST_ARRAY(v), GValue, (index))) 127 128 static GArray *gst_value_table; 129 static GHashTable *gst_value_hash; 130 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1]; 131 static GArray *gst_value_union_funcs; 132 static GArray *gst_value_intersect_funcs; 133 static GArray *gst_value_subtract_funcs; 134 135 /* Forward declarations */ 136 static gchar *gst_value_serialize_fraction (const GValue * value); 137 138 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1); 139 static gint gst_value_compare_with_func (const GValue * value1, 140 const GValue * value2, GstValueCompareFunc compare); 141 142 static gchar *gst_string_wrap (const gchar * s); 143 static gchar *gst_string_take_and_wrap (gchar * s); 144 static gchar *gst_string_unwrap (const gchar * s); 145 146 static void gst_value_move (GValue * dest, GValue * src); 147 static void _gst_value_list_append_and_take_value (GValue * value, 148 GValue * append_value); 149 static void _gst_value_array_append_and_take_value (GValue * value, 150 GValue * append_value); 151 152 static inline GstValueTable * 153 gst_value_hash_lookup_type (GType type) 154 { 155 if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type))) 156 return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)]; 157 else 158 return g_hash_table_lookup (gst_value_hash, (gpointer) type); 159 } 160 161 static void 162 gst_value_hash_add_type (GType type, const GstValueTable * table) 163 { 164 if (G_TYPE_IS_FUNDAMENTAL (type)) 165 gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table; 166 167 g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table); 168 } 169 170 /******** 171 * list * 172 ********/ 173 174 /* two helper functions to serialize/stringify any type of list 175 * regular lists are done with { }, arrays with < > 176 */ 177 static gchar * 178 gst_value_serialize_any_list (const GValue * value, const gchar * begin, 179 const gchar * end) 180 { 181 guint i; 182 GArray *array = value->data[0].v_pointer; 183 GString *s; 184 GValue *v; 185 gchar *s_val; 186 guint alen = array->len; 187 188 /* estimate minimum string length to minimise re-allocs in GString */ 189 s = g_string_sized_new (2 + (6 * alen) + 2); 190 g_string_append (s, begin); 191 for (i = 0; i < alen; i++) { 192 v = &g_array_index (array, GValue, i); 193 s_val = gst_value_serialize (v); 194 if (s_val != NULL) { 195 g_string_append (s, s_val); 196 g_free (s_val); 197 if (i < alen - 1) { 198 g_string_append_len (s, ", ", 2); 199 } 200 } else { 201 GST_WARNING ("Could not serialize list/array value of type '%s'", 202 G_VALUE_TYPE_NAME (v)); 203 } 204 } 205 g_string_append (s, end); 206 return g_string_free (s, FALSE); 207 } 208 209 static void 210 gst_value_transform_any_list_string (const GValue * src_value, 211 GValue * dest_value, const gchar * begin, const gchar * end) 212 { 213 GValue *list_value; 214 GArray *array; 215 GString *s; 216 guint i; 217 gchar *list_s; 218 guint alen; 219 220 array = src_value->data[0].v_pointer; 221 alen = array->len; 222 223 /* estimate minimum string length to minimise re-allocs in GString */ 224 s = g_string_sized_new (2 + (10 * alen) + 2); 225 g_string_append (s, begin); 226 for (i = 0; i < alen; i++) { 227 list_value = &g_array_index (array, GValue, i); 228 229 if (i != 0) { 230 g_string_append_len (s, ", ", 2); 231 } 232 list_s = g_strdup_value_contents (list_value); 233 g_string_append (s, list_s); 234 g_free (list_s); 235 } 236 g_string_append (s, end); 237 238 dest_value->data[0].v_pointer = g_string_free (s, FALSE); 239 } 240 241 /* 242 * helper function to see if a type is fixed. Is used internally here and 243 * there. Do not export, since it doesn't work for types where the content 244 * decides the fixedness (e.g. GST_TYPE_ARRAY). 245 */ 246 static gboolean 247 gst_type_is_fixed (GType type) 248 { 249 /* the basic int, string, double types */ 250 if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) { 251 return TRUE; 252 } 253 /* our fundamental types that are certainly not fixed */ 254 if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE || 255 type == GST_TYPE_INT64_RANGE || 256 type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) { 257 return FALSE; 258 } 259 /* other (boxed) types that are fixed */ 260 if (type == GST_TYPE_BUFFER) { 261 return TRUE; 262 } 263 /* heavy checks */ 264 if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <= 265 G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) { 266 return TRUE; 267 } 268 269 return FALSE; 270 } 271 272 /* GValue functions usable for both regular lists and arrays */ 273 static void 274 gst_value_init_list_or_array (GValue * value) 275 { 276 value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue)); 277 } 278 279 static GArray * 280 copy_garray_of_gstvalue (const GArray * src) 281 { 282 GArray *dest; 283 guint i, len; 284 285 len = src->len; 286 dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len); 287 g_array_set_size (dest, len); 288 for (i = 0; i < len; i++) { 289 gst_value_init_and_copy (&g_array_index (dest, GValue, i), 290 &g_array_index (src, GValue, i)); 291 } 292 293 return dest; 294 } 295 296 static void 297 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value) 298 { 299 dest_value->data[0].v_pointer = 300 copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer); 301 } 302 303 static void 304 gst_value_free_list_or_array (GValue * value) 305 { 306 guint i, len; 307 GArray *src = (GArray *) value->data[0].v_pointer; 308 len = src->len; 309 310 if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) { 311 for (i = 0; i < len; i++) { 312 g_value_unset (&g_array_index (src, GValue, i)); 313 } 314 g_array_free (src, TRUE); 315 } 316 } 317 318 static gpointer 319 gst_value_list_or_array_peek_pointer (const GValue * value) 320 { 321 return value->data[0].v_pointer; 322 } 323 324 static gchar * 325 gst_value_collect_list_or_array (GValue * value, guint n_collect_values, 326 GTypeCValue * collect_values, guint collect_flags) 327 { 328 if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { 329 value->data[0].v_pointer = collect_values[0].v_pointer; 330 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS; 331 } else { 332 value->data[0].v_pointer = 333 copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer); 334 } 335 return NULL; 336 } 337 338 static gchar * 339 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values, 340 GTypeCValue * collect_values, guint collect_flags) 341 { 342 GArray **dest = collect_values[0].v_pointer; 343 344 if (!dest) 345 return g_strdup_printf ("value location for `%s' passed as NULL", 346 G_VALUE_TYPE_NAME (value)); 347 if (!value->data[0].v_pointer) 348 return g_strdup_printf ("invalid value given for `%s'", 349 G_VALUE_TYPE_NAME (value)); 350 if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { 351 *dest = (GArray *) value->data[0].v_pointer; 352 } else { 353 *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer); 354 } 355 return NULL; 356 } 357 358 static gboolean 359 gst_value_list_or_array_get_basic_type (const GValue * value, GType * type) 360 { 361 if (G_UNLIKELY (value == NULL)) 362 return FALSE; 363 364 if (GST_VALUE_HOLDS_LIST (value)) { 365 if (VALUE_LIST_SIZE (value) == 0) 366 return FALSE; 367 return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value, 368 0), type); 369 } 370 if (GST_VALUE_HOLDS_ARRAY (value)) { 371 const GArray *array = (const GArray *) value->data[0].v_pointer; 372 if (array->len == 0) 373 return FALSE; 374 return gst_value_list_or_array_get_basic_type (&g_array_index (array, 375 GValue, 0), type); 376 } 377 378 *type = G_VALUE_TYPE (value); 379 380 return TRUE; 381 } 382 383 #define IS_RANGE_COMPAT(type1,type2,t1,t2) \ 384 (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2))) 385 386 static gboolean 387 gst_value_list_or_array_are_compatible (const GValue * value1, 388 const GValue * value2) 389 { 390 GType basic_type1, basic_type2; 391 392 /* empty or same type is OK */ 393 if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) || 394 !gst_value_list_or_array_get_basic_type (value2, &basic_type2) || 395 basic_type1 == basic_type2) 396 return TRUE; 397 398 /* ranges are distinct types for each bound type... */ 399 if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1, 400 basic_type2)) 401 return TRUE; 402 if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1, 403 basic_type2)) 404 return TRUE; 405 if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1, 406 basic_type2)) 407 return TRUE; 408 if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1, 409 basic_type2)) 410 return TRUE; 411 412 return FALSE; 413 } 414 415 static inline void 416 _gst_value_list_append_and_take_value (GValue * value, GValue * append_value) 417 { 418 g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1); 419 memset (append_value, 0, sizeof (GValue)); 420 } 421 422 /** 423 * gst_value_list_append_and_take_value: 424 * @value: a #GValue of type #GST_TYPE_LIST 425 * @append_value: (transfer full): the value to append 426 * 427 * Appends @append_value to the GstValueList in @value. 428 * 429 * Since: 1.2 430 */ 431 void 432 gst_value_list_append_and_take_value (GValue * value, GValue * append_value) 433 { 434 g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); 435 g_return_if_fail (G_IS_VALUE (append_value)); 436 g_return_if_fail (gst_value_list_or_array_are_compatible (value, 437 append_value)); 438 439 _gst_value_list_append_and_take_value (value, append_value); 440 } 441 442 /** 443 * gst_value_list_append_value: 444 * @value: a #GValue of type #GST_TYPE_LIST 445 * @append_value: (transfer none): the value to append 446 * 447 * Appends @append_value to the GstValueList in @value. 448 */ 449 void 450 gst_value_list_append_value (GValue * value, const GValue * append_value) 451 { 452 GValue val = { 0, }; 453 454 g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); 455 g_return_if_fail (G_IS_VALUE (append_value)); 456 g_return_if_fail (gst_value_list_or_array_are_compatible (value, 457 append_value)); 458 459 gst_value_init_and_copy (&val, append_value); 460 g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1); 461 } 462 463 /** 464 * gst_value_list_prepend_value: 465 * @value: a #GValue of type #GST_TYPE_LIST 466 * @prepend_value: the value to prepend 467 * 468 * Prepends @prepend_value to the GstValueList in @value. 469 */ 470 void 471 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value) 472 { 473 GValue val = { 0, }; 474 475 g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); 476 g_return_if_fail (G_IS_VALUE (prepend_value)); 477 g_return_if_fail (gst_value_list_or_array_are_compatible (value, 478 prepend_value)); 479 480 gst_value_init_and_copy (&val, prepend_value); 481 g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1); 482 } 483 484 /** 485 * gst_value_list_concat: 486 * @dest: (out caller-allocates): an uninitialized #GValue to take the result 487 * @value1: a #GValue 488 * @value2: a #GValue 489 * 490 * Concatenates copies of @value1 and @value2 into a list. Values that are not 491 * of type #GST_TYPE_LIST are treated as if they were lists of length 1. 492 * @dest will be initialized to the type #GST_TYPE_LIST. 493 */ 494 void 495 gst_value_list_concat (GValue * dest, const GValue * value1, 496 const GValue * value2) 497 { 498 guint i, value1_length, value2_length; 499 GArray *array; 500 501 g_return_if_fail (dest != NULL); 502 g_return_if_fail (G_VALUE_TYPE (dest) == 0); 503 g_return_if_fail (G_IS_VALUE (value1)); 504 g_return_if_fail (G_IS_VALUE (value2)); 505 g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2)); 506 507 value1_length = 508 (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1); 509 value2_length = 510 (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1); 511 g_value_init (dest, GST_TYPE_LIST); 512 array = (GArray *) dest->data[0].v_pointer; 513 g_array_set_size (array, value1_length + value2_length); 514 515 if (GST_VALUE_HOLDS_LIST (value1)) { 516 for (i = 0; i < value1_length; i++) { 517 gst_value_init_and_copy (&g_array_index (array, GValue, i), 518 VALUE_LIST_GET_VALUE (value1, i)); 519 } 520 } else { 521 gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1); 522 } 523 524 if (GST_VALUE_HOLDS_LIST (value2)) { 525 for (i = 0; i < value2_length; i++) { 526 gst_value_init_and_copy (&g_array_index (array, GValue, 527 i + value1_length), VALUE_LIST_GET_VALUE (value2, i)); 528 } 529 } else { 530 gst_value_init_and_copy (&g_array_index (array, GValue, value1_length), 531 value2); 532 } 533 } 534 535 /* same as gst_value_list_concat() but takes ownership of GValues */ 536 static void 537 gst_value_list_concat_and_take_values (GValue * dest, GValue * val1, 538 GValue * val2) 539 { 540 guint i, val1_length, val2_length; 541 gboolean val1_is_list; 542 gboolean val2_is_list; 543 GArray *array; 544 545 g_assert (dest != NULL); 546 g_assert (G_VALUE_TYPE (dest) == 0); 547 g_assert (G_IS_VALUE (val1)); 548 g_assert (G_IS_VALUE (val2)); 549 g_assert (gst_value_list_or_array_are_compatible (val1, val2)); 550 551 val1_is_list = GST_VALUE_HOLDS_LIST (val1); 552 val1_length = (val1_is_list ? VALUE_LIST_SIZE (val1) : 1); 553 554 val2_is_list = GST_VALUE_HOLDS_LIST (val2); 555 val2_length = (val2_is_list ? VALUE_LIST_SIZE (val2) : 1); 556 557 g_value_init (dest, GST_TYPE_LIST); 558 array = (GArray *) dest->data[0].v_pointer; 559 g_array_set_size (array, val1_length + val2_length); 560 561 if (val1_is_list) { 562 for (i = 0; i < val1_length; i++) { 563 g_array_index (array, GValue, i) = *VALUE_LIST_GET_VALUE (val1, i); 564 } 565 g_array_set_size (VALUE_LIST_ARRAY (val1), 0); 566 g_value_unset (val1); 567 } else { 568 g_array_index (array, GValue, 0) = *val1; 569 G_VALUE_TYPE (val1) = G_TYPE_INVALID; 570 } 571 572 if (val2_is_list) { 573 for (i = 0; i < val2_length; i++) { 574 const GValue *v2 = VALUE_LIST_GET_VALUE (val2, i); 575 g_array_index (array, GValue, i + val1_length) = *v2; 576 } 577 g_array_set_size (VALUE_LIST_ARRAY (val2), 0); 578 g_value_unset (val2); 579 } else { 580 g_array_index (array, GValue, val1_length) = *val2; 581 G_VALUE_TYPE (val2) = G_TYPE_INVALID; 582 } 583 } 584 585 /** 586 * gst_value_list_merge: 587 * @dest: (out caller-allocates): an uninitialized #GValue to take the result 588 * @value1: a #GValue 589 * @value2: a #GValue 590 * 591 * Merges copies of @value1 and @value2. Values that are not 592 * of type #GST_TYPE_LIST are treated as if they were lists of length 1. 593 * 594 * The result will be put into @dest and will either be a list that will not 595 * contain any duplicates, or a non-list type (if @value1 and @value2 596 * were equal). 597 */ 598 void 599 gst_value_list_merge (GValue * dest, const GValue * value1, 600 const GValue * value2) 601 { 602 guint i, j, k, value1_length, value2_length, skipped; 603 const GValue *src; 604 gboolean skip; 605 GArray *array; 606 607 g_return_if_fail (dest != NULL); 608 g_return_if_fail (G_VALUE_TYPE (dest) == 0); 609 g_return_if_fail (G_IS_VALUE (value1)); 610 g_return_if_fail (G_IS_VALUE (value2)); 611 g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2)); 612 613 value1_length = 614 (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1); 615 value2_length = 616 (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1); 617 g_value_init (dest, GST_TYPE_LIST); 618 array = (GArray *) dest->data[0].v_pointer; 619 g_array_set_size (array, value1_length + value2_length); 620 621 if (GST_VALUE_HOLDS_LIST (value1)) { 622 for (i = 0; i < value1_length; i++) { 623 gst_value_init_and_copy (&g_array_index (array, GValue, i), 624 VALUE_LIST_GET_VALUE (value1, i)); 625 } 626 } else { 627 gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1); 628 } 629 630 j = value1_length; 631 skipped = 0; 632 if (GST_VALUE_HOLDS_LIST (value2)) { 633 for (i = 0; i < value2_length; i++) { 634 skip = FALSE; 635 src = VALUE_LIST_GET_VALUE (value2, i); 636 for (k = 0; k < value1_length; k++) { 637 if (gst_value_compare (&g_array_index (array, GValue, k), 638 src) == GST_VALUE_EQUAL) { 639 skip = TRUE; 640 skipped++; 641 break; 642 } 643 } 644 if (!skip) { 645 gst_value_init_and_copy (&g_array_index (array, GValue, j), src); 646 j++; 647 } 648 } 649 } else { 650 skip = FALSE; 651 for (k = 0; k < value1_length; k++) { 652 if (gst_value_compare (&g_array_index (array, GValue, k), 653 value2) == GST_VALUE_EQUAL) { 654 skip = TRUE; 655 skipped++; 656 break; 657 } 658 } 659 if (!skip) { 660 gst_value_init_and_copy (&g_array_index (array, GValue, j), value2); 661 } 662 } 663 if (skipped) { 664 guint new_size = value1_length + (value2_length - skipped); 665 666 if (new_size > 1) { 667 /* shrink list */ 668 g_array_set_size (array, new_size); 669 } else { 670 GValue single_dest; 671 672 /* size is 1, take single value in list and make it new dest */ 673 single_dest = g_array_index (array, GValue, 0); 674 675 /* clean up old value allocations: must set array size to 0, because 676 * allocated values are not inited meaning g_value_unset() will not 677 * work on them */ 678 g_array_set_size (array, 0); 679 g_value_unset (dest); 680 681 /* the single value is our new result */ 682 *dest = single_dest; 683 } 684 } 685 } 686 687 /** 688 * gst_value_list_get_size: 689 * @value: a #GValue of type #GST_TYPE_LIST 690 * 691 * Gets the number of values contained in @value. 692 * 693 * Returns: the number of values 694 */ 695 guint 696 gst_value_list_get_size (const GValue * value) 697 { 698 g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0); 699 700 return ((GArray *) value->data[0].v_pointer)->len; 701 } 702 703 /** 704 * gst_value_list_get_value: 705 * @value: a #GValue of type #GST_TYPE_LIST 706 * @index: index of value to get from the list 707 * 708 * Gets the value that is a member of the list contained in @value and 709 * has the index @index. 710 * 711 * Returns: (transfer none): the value at the given index 712 */ 713 const GValue * 714 gst_value_list_get_value (const GValue * value, guint index) 715 { 716 g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL); 717 g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL); 718 719 return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, 720 GValue, index); 721 } 722 723 /** 724 * gst_value_array_append_value: 725 * @value: a #GValue of type #GST_TYPE_ARRAY 726 * @append_value: the value to append 727 * 728 * Appends @append_value to the GstValueArray in @value. 729 */ 730 void 731 gst_value_array_append_value (GValue * value, const GValue * append_value) 732 { 733 GValue val = { 0, }; 734 735 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); 736 g_return_if_fail (G_IS_VALUE (append_value)); 737 g_return_if_fail (gst_value_list_or_array_are_compatible (value, 738 append_value)); 739 740 gst_value_init_and_copy (&val, append_value); 741 g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1); 742 } 743 744 static inline void 745 _gst_value_array_append_and_take_value (GValue * value, GValue * append_value) 746 { 747 g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1); 748 memset (append_value, 0, sizeof (GValue)); 749 } 750 751 /** 752 * gst_value_array_append_and_take_value: 753 * @value: a #GValue of type #GST_TYPE_ARRAY 754 * @append_value: (transfer full): the value to append 755 * 756 * Appends @append_value to the GstValueArray in @value. 757 * 758 * Since: 1.2 759 */ 760 void 761 gst_value_array_append_and_take_value (GValue * value, GValue * append_value) 762 { 763 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); 764 g_return_if_fail (G_IS_VALUE (append_value)); 765 g_return_if_fail (gst_value_list_or_array_are_compatible (value, 766 append_value)); 767 768 _gst_value_array_append_and_take_value (value, append_value); 769 } 770 771 #ifndef GSTREAMER_LITE 772 /** 773 * gst_value_array_prepend_value: 774 * @value: a #GValue of type #GST_TYPE_ARRAY 775 * @prepend_value: the value to prepend 776 * 777 * Prepends @prepend_value to the GstValueArray in @value. 778 */ 779 void 780 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value) 781 { 782 GValue val = { 0, }; 783 784 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); 785 g_return_if_fail (G_IS_VALUE (prepend_value)); 786 g_return_if_fail (gst_value_list_or_array_are_compatible (value, 787 prepend_value)); 788 789 gst_value_init_and_copy (&val, prepend_value); 790 g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1); 791 } 792 #endif // GSTREAMER_LITE 793 794 /** 795 * gst_value_array_get_size: 796 * @value: a #GValue of type #GST_TYPE_ARRAY 797 * 798 * Gets the number of values contained in @value. 799 * 800 * Returns: the number of values 801 */ 802 guint 803 gst_value_array_get_size (const GValue * value) 804 { 805 g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0); 806 807 return ((GArray *) value->data[0].v_pointer)->len; 808 } 809 810 /** 811 * gst_value_array_get_value: 812 * @value: a #GValue of type #GST_TYPE_ARRAY 813 * @index: index of value to get from the array 814 * 815 * Gets the value that is a member of the array contained in @value and 816 * has the index @index. 817 * 818 * Returns: (transfer none): the value at the given index 819 */ 820 const GValue * 821 gst_value_array_get_value (const GValue * value, guint index) 822 { 823 g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL); 824 g_return_val_if_fail (index < gst_value_array_get_size (value), NULL); 825 826 return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, 827 GValue, index); 828 } 829 830 static void 831 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value) 832 { 833 gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }"); 834 } 835 836 static void 837 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value) 838 { 839 gst_value_transform_any_list_string (src_value, dest_value, "< ", " >"); 840 } 841 842 /* Do an unordered compare of the contents of a list */ 843 static gint 844 gst_value_compare_list (const GValue * value1, const GValue * value2) 845 { 846 guint i, j; 847 GArray *array1 = value1->data[0].v_pointer; 848 GArray *array2 = value2->data[0].v_pointer; 849 GValue *v1; 850 GValue *v2; 851 gint len, to_remove; 852 guint8 *removed; 853 GstValueCompareFunc compare; 854 855 /* get length and do initial length check. */ 856 len = array1->len; 857 if (len != array2->len) 858 return GST_VALUE_UNORDERED; 859 860 /* place to mark removed value indices of array2 */ 861 removed = g_newa (guint8, len); 862 memset (removed, 0, len); 863 to_remove = len; 864 865 /* loop over array1, all items should be in array2. When we find an 866 * item in array2, remove it from array2 by marking it as removed */ 867 for (i = 0; i < len; i++) { 868 v1 = &g_array_index (array1, GValue, i); 869 if ((compare = gst_value_get_compare_func (v1))) { 870 for (j = 0; j < len; j++) { 871 /* item is removed, we can skip it */ 872 if (removed[j]) 873 continue; 874 v2 = &g_array_index (array2, GValue, j); 875 if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) { 876 /* mark item as removed now that we found it in array2 and 877 * decrement the number of remaining items in array2. */ 878 removed[j] = 1; 879 to_remove--; 880 break; 881 } 882 } 883 /* item in array1 and not in array2, UNORDERED */ 884 if (j == len) 885 return GST_VALUE_UNORDERED; 886 } else 887 return GST_VALUE_UNORDERED; 888 } 889 /* if not all items were removed, array2 contained something not in array1 */ 890 if (to_remove != 0) 891 return GST_VALUE_UNORDERED; 892 893 /* arrays are equal */ 894 return GST_VALUE_EQUAL; 895 } 896 897 /* Perform an ordered comparison of the contents of an array */ 898 static gint 899 gst_value_compare_array (const GValue * value1, const GValue * value2) 900 { 901 guint i; 902 GArray *array1 = value1->data[0].v_pointer; 903 GArray *array2 = value2->data[0].v_pointer; 904 guint len = array1->len; 905 GValue *v1; 906 GValue *v2; 907 908 if (len != array2->len) 909 return GST_VALUE_UNORDERED; 910 911 for (i = 0; i < len; i++) { 912 v1 = &g_array_index (array1, GValue, i); 913 v2 = &g_array_index (array2, GValue, i); 914 if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL) 915 return GST_VALUE_UNORDERED; 916 } 917 918 return GST_VALUE_EQUAL; 919 } 920 921 static gchar * 922 gst_value_serialize_list (const GValue * value) 923 { 924 return gst_value_serialize_any_list (value, "{ ", " }"); 925 } 926 927 static gboolean 928 gst_value_deserialize_list (GValue * dest, const gchar * s) 929 { 930 g_warning ("gst_value_deserialize_list: unimplemented"); 931 return FALSE; 932 } 933 934 static gchar * 935 gst_value_serialize_array (const GValue * value) 936 { 937 return gst_value_serialize_any_list (value, "< ", " >"); 938 } 939 940 static gboolean 941 gst_value_deserialize_array (GValue * dest, const gchar * s) 942 { 943 g_warning ("gst_value_deserialize_array: unimplemented"); 944 return FALSE; 945 } 946 947 /************* 948 * int range * 949 * 950 * Values in the range are defined as any value greater or equal 951 * to min*step, AND lesser or equal to max*step. 952 * For step == 1, this falls back to the traditional range semantics. 953 * 954 * data[0] = (min << 32) | (max) 955 * data[1] = step 956 * 957 *************/ 958 959 #define INT_RANGE_MIN(v) ((gint) (((v)->data[0].v_uint64) >> 32)) 960 #define INT_RANGE_MAX(v) ((gint) (((v)->data[0].v_uint64) & 0xffffffff)) 961 #define INT_RANGE_STEP(v) ((v)->data[1].v_int) 962 963 static void 964 gst_value_init_int_range (GValue * value) 965 { 966 G_STATIC_ASSERT (sizeof (gint) <= 2 * sizeof (guint64)); 967 968 value->data[0].v_uint64 = 0; 969 value->data[1].v_int = 1; 970 } 971 972 static void 973 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value) 974 { 975 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; 976 dest_value->data[1].v_int = src_value->data[1].v_int; 977 } 978 979 static gchar * 980 gst_value_collect_int_range (GValue * value, guint n_collect_values, 981 GTypeCValue * collect_values, guint collect_flags) 982 { 983 if (n_collect_values != 2) 984 return g_strdup_printf ("not enough value locations for `%s' passed", 985 G_VALUE_TYPE_NAME (value)); 986 if (collect_values[0].v_int >= collect_values[1].v_int) 987 return g_strdup_printf ("range start is not smaller than end for `%s'", 988 G_VALUE_TYPE_NAME (value)); 989 990 gst_value_set_int_range_step (value, collect_values[0].v_int, 991 collect_values[1].v_int, 1); 992 993 return NULL; 994 } 995 996 static gchar * 997 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values, 998 GTypeCValue * collect_values, guint collect_flags) 999 { 1000 guint32 *int_range_start = collect_values[0].v_pointer; 1001 guint32 *int_range_end = collect_values[1].v_pointer; 1002 1003 if (!int_range_start) 1004 return g_strdup_printf ("start value location for `%s' passed as NULL", 1005 G_VALUE_TYPE_NAME (value)); 1006 if (!int_range_end) 1007 return g_strdup_printf ("end value location for `%s' passed as NULL", 1008 G_VALUE_TYPE_NAME (value)); 1009 1010 *int_range_start = INT_RANGE_MIN (value); 1011 *int_range_end = INT_RANGE_MAX (value); 1012 1013 return NULL; 1014 } 1015 1016 /** 1017 * gst_value_set_int_range_step: 1018 * @value: a GValue initialized to GST_TYPE_INT_RANGE 1019 * @start: the start of the range 1020 * @end: the end of the range 1021 * @step: the step of the range 1022 * 1023 * Sets @value to the range specified by @start, @end and @step. 1024 */ 1025 void 1026 gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step) 1027 { 1028 guint64 sstart, sstop; 1029 1030 g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value)); 1031 g_return_if_fail (start < end); 1032 g_return_if_fail (step > 0); 1033 g_return_if_fail (start % step == 0); 1034 g_return_if_fail (end % step == 0); 1035 1036 sstart = (guint) (start / step); 1037 sstop = (guint) (end / step); 1038 value->data[0].v_uint64 = (sstart << 32) | sstop; 1039 value->data[1].v_int = step; 1040 } 1041 1042 /** 1043 * gst_value_set_int_range: 1044 * @value: a GValue initialized to GST_TYPE_INT_RANGE 1045 * @start: the start of the range 1046 * @end: the end of the range 1047 * 1048 * Sets @value to the range specified by @start and @end. 1049 */ 1050 void 1051 gst_value_set_int_range (GValue * value, gint start, gint end) 1052 { 1053 gst_value_set_int_range_step (value, start, end, 1); 1054 } 1055 1056 /** 1057 * gst_value_get_int_range_min: 1058 * @value: a GValue initialized to GST_TYPE_INT_RANGE 1059 * 1060 * Gets the minimum of the range specified by @value. 1061 * 1062 * Returns: the minimum of the range 1063 */ 1064 gint 1065 gst_value_get_int_range_min (const GValue * value) 1066 { 1067 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); 1068 1069 return INT_RANGE_MIN (value) * INT_RANGE_STEP (value); 1070 } 1071 1072 /** 1073 * gst_value_get_int_range_max: 1074 * @value: a GValue initialized to GST_TYPE_INT_RANGE 1075 * 1076 * Gets the maximum of the range specified by @value. 1077 * 1078 * Returns: the maximum of the range 1079 */ 1080 gint 1081 gst_value_get_int_range_max (const GValue * value) 1082 { 1083 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); 1084 1085 return INT_RANGE_MAX (value) * INT_RANGE_STEP (value); 1086 } 1087 1088 /** 1089 * gst_value_get_int_range_step: 1090 * @value: a GValue initialized to GST_TYPE_INT_RANGE 1091 * 1092 * Gets the step of the range specified by @value. 1093 * 1094 * Returns: the step of the range 1095 */ 1096 gint 1097 gst_value_get_int_range_step (const GValue * value) 1098 { 1099 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); 1100 1101 return INT_RANGE_STEP (value); 1102 } 1103 1104 static void 1105 gst_value_transform_int_range_string (const GValue * src_value, 1106 GValue * dest_value) 1107 { 1108 if (INT_RANGE_STEP (src_value) == 1) 1109 dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]", 1110 INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value)); 1111 else 1112 dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]", 1113 INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value), 1114 INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value), 1115 INT_RANGE_STEP (src_value)); 1116 } 1117 1118 static gint 1119 gst_value_compare_int_range (const GValue * value1, const GValue * value2) 1120 { 1121 /* calculate the number of values in each range */ 1122 gint n1 = INT_RANGE_MAX (value1) - INT_RANGE_MIN (value1) + 1; 1123 gint n2 = INT_RANGE_MAX (value2) - INT_RANGE_MIN (value2) + 1; 1124 1125 /* they must be equal */ 1126 if (n1 != n2) 1127 return GST_VALUE_UNORDERED; 1128 1129 /* if empty, equal */ 1130 if (n1 == 0) 1131 return GST_VALUE_EQUAL; 1132 1133 /* if more than one value, then it is only equal if the step is equal 1134 and bounds lie on the same value */ 1135 if (n1 > 1) { 1136 if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) && 1137 INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2) && 1138 INT_RANGE_MAX (value1) == INT_RANGE_MAX (value2)) { 1139 return GST_VALUE_EQUAL; 1140 } 1141 return GST_VALUE_UNORDERED; 1142 } else { 1143 /* if just one, only if the value is equal */ 1144 if (INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2)) 1145 return GST_VALUE_EQUAL; 1146 return GST_VALUE_UNORDERED; 1147 } 1148 } 1149 1150 static gchar * 1151 gst_value_serialize_int_range (const GValue * value) 1152 { 1153 if (INT_RANGE_STEP (value) == 1) 1154 return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value), 1155 INT_RANGE_MAX (value)); 1156 else 1157 return g_strdup_printf ("[ %d, %d, %d ]", 1158 INT_RANGE_MIN (value) * INT_RANGE_STEP (value), 1159 INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value)); 1160 } 1161 1162 static gboolean 1163 gst_value_deserialize_int_range (GValue * dest, const gchar * s) 1164 { 1165 g_warning ("unimplemented"); 1166 return FALSE; 1167 } 1168 1169 /*************** 1170 * int64 range * 1171 * 1172 * Values in the range are defined as any value greater or equal 1173 * to min*step, AND lesser or equal to max*step. 1174 * For step == 1, this falls back to the traditional range semantics. 1175 ***************/ 1176 1177 #define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0]) 1178 #define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1]) 1179 #define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2]) 1180 1181 static void 1182 gst_value_init_int64_range (GValue * value) 1183 { 1184 gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64)); 1185 value->data[0].v_pointer = vals; 1186 INT64_RANGE_MIN (value) = 0; 1187 INT64_RANGE_MAX (value) = 0; 1188 INT64_RANGE_STEP (value) = 1; 1189 } 1190 1191 static void 1192 gst_value_free_int64_range (GValue * value) 1193 { 1194 g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value)); 1195 g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer); 1196 value->data[0].v_pointer = NULL; 1197 } 1198 1199 static void 1200 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value) 1201 { 1202 gint64 *vals = (gint64 *) dest_value->data[0].v_pointer; 1203 gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer; 1204 1205 if (vals == NULL) { 1206 gst_value_init_int64_range (dest_value); 1207 } 1208 1209 if (src_vals != NULL) { 1210 INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value); 1211 INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value); 1212 INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value); 1213 } 1214 } 1215 1216 static gchar * 1217 gst_value_collect_int64_range (GValue * value, guint n_collect_values, 1218 GTypeCValue * collect_values, guint collect_flags) 1219 { 1220 gint64 *vals = value->data[0].v_pointer; 1221 1222 if (n_collect_values != 2) 1223 return g_strdup_printf ("not enough value locations for `%s' passed", 1224 G_VALUE_TYPE_NAME (value)); 1225 if (collect_values[0].v_int64 >= collect_values[1].v_int64) 1226 return g_strdup_printf ("range start is not smaller than end for `%s'", 1227 G_VALUE_TYPE_NAME (value)); 1228 1229 if (vals == NULL) { 1230 gst_value_init_int64_range (value); 1231 } 1232 1233 gst_value_set_int64_range_step (value, collect_values[0].v_int64, 1234 collect_values[1].v_int64, 1); 1235 1236 return NULL; 1237 } 1238 1239 static gchar * 1240 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values, 1241 GTypeCValue * collect_values, guint collect_flags) 1242 { 1243 guint64 *int_range_start = collect_values[0].v_pointer; 1244 guint64 *int_range_end = collect_values[1].v_pointer; 1245 guint64 *int_range_step = collect_values[2].v_pointer; 1246 gint64 *vals = (gint64 *) value->data[0].v_pointer; 1247 1248 if (!int_range_start) 1249 return g_strdup_printf ("start value location for `%s' passed as NULL", 1250 G_VALUE_TYPE_NAME (value)); 1251 if (!int_range_end) 1252 return g_strdup_printf ("end value location for `%s' passed as NULL", 1253 G_VALUE_TYPE_NAME (value)); 1254 if (!int_range_step) 1255 return g_strdup_printf ("step value location for `%s' passed as NULL", 1256 G_VALUE_TYPE_NAME (value)); 1257 1258 if (G_UNLIKELY (vals == NULL)) { 1259 return g_strdup_printf ("Uninitialised `%s' passed", 1260 G_VALUE_TYPE_NAME (value)); 1261 } 1262 1263 *int_range_start = INT64_RANGE_MIN (value); 1264 *int_range_end = INT64_RANGE_MAX (value); 1265 *int_range_step = INT64_RANGE_STEP (value); 1266 1267 return NULL; 1268 } 1269 1270 /** 1271 * gst_value_set_int64_range_step: 1272 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1273 * @start: the start of the range 1274 * @end: the end of the range 1275 * @step: the step of the range 1276 * 1277 * Sets @value to the range specified by @start, @end and @step. 1278 */ 1279 void 1280 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end, 1281 gint64 step) 1282 { 1283 g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value)); 1284 g_return_if_fail (start < end); 1285 g_return_if_fail (step > 0); 1286 g_return_if_fail (start % step == 0); 1287 g_return_if_fail (end % step == 0); 1288 1289 INT64_RANGE_MIN (value) = start / step; 1290 INT64_RANGE_MAX (value) = end / step; 1291 INT64_RANGE_STEP (value) = step; 1292 } 1293 1294 /** 1295 * gst_value_set_int64_range: 1296 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1297 * @start: the start of the range 1298 * @end: the end of the range 1299 * 1300 * Sets @value to the range specified by @start and @end. 1301 */ 1302 void 1303 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end) 1304 { 1305 gst_value_set_int64_range_step (value, start, end, 1); 1306 } 1307 1308 /** 1309 * gst_value_get_int64_range_min: 1310 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1311 * 1312 * Gets the minimum of the range specified by @value. 1313 * 1314 * Returns: the minimum of the range 1315 */ 1316 gint64 1317 gst_value_get_int64_range_min (const GValue * value) 1318 { 1319 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); 1320 1321 return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value); 1322 } 1323 1324 /** 1325 * gst_value_get_int64_range_max: 1326 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1327 * 1328 * Gets the maximum of the range specified by @value. 1329 * 1330 * Returns: the maximum of the range 1331 */ 1332 gint64 1333 gst_value_get_int64_range_max (const GValue * value) 1334 { 1335 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); 1336 1337 return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value); 1338 } 1339 1340 /** 1341 * gst_value_get_int64_range_step: 1342 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1343 * 1344 * Gets the step of the range specified by @value. 1345 * 1346 * Returns: the step of the range 1347 */ 1348 gint64 1349 gst_value_get_int64_range_step (const GValue * value) 1350 { 1351 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); 1352 1353 return INT64_RANGE_STEP (value); 1354 } 1355 1356 static void 1357 gst_value_transform_int64_range_string (const GValue * src_value, 1358 GValue * dest_value) 1359 { 1360 if (INT64_RANGE_STEP (src_value) == 1) 1361 dest_value->data[0].v_pointer = 1362 g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]", 1363 INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value)); 1364 else 1365 dest_value->data[0].v_pointer = 1366 g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT 1367 ",%" G_GINT64_FORMAT "]", 1368 INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value), 1369 INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value), 1370 INT64_RANGE_STEP (src_value)); 1371 } 1372 1373 static gint 1374 gst_value_compare_int64_range (const GValue * value1, const GValue * value2) 1375 { 1376 /* calculate the number of values in each range */ 1377 gint64 n1 = INT64_RANGE_MAX (value1) - INT64_RANGE_MIN (value1) + 1; 1378 gint64 n2 = INT64_RANGE_MAX (value2) - INT64_RANGE_MIN (value2) + 1; 1379 1380 /* they must be equal */ 1381 if (n1 != n2) 1382 return GST_VALUE_UNORDERED; 1383 1384 /* if empty, equal */ 1385 if (n1 == 0) 1386 return GST_VALUE_EQUAL; 1387 1388 /* if more than one value, then it is only equal if the step is equal 1389 and bounds lie on the same value */ 1390 if (n1 > 1) { 1391 if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) && 1392 INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2) && 1393 INT64_RANGE_MAX (value1) == INT64_RANGE_MAX (value2)) { 1394 return GST_VALUE_EQUAL; 1395 } 1396 return GST_VALUE_UNORDERED; 1397 } else { 1398 /* if just one, only if the value is equal */ 1399 if (INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2)) 1400 return GST_VALUE_EQUAL; 1401 return GST_VALUE_UNORDERED; 1402 } 1403 } 1404 1405 static gchar * 1406 gst_value_serialize_int64_range (const GValue * value) 1407 { 1408 if (INT64_RANGE_STEP (value) == 1) 1409 return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]", 1410 INT64_RANGE_MIN (value), INT64_RANGE_MAX (value)); 1411 else 1412 return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %" 1413 G_GINT64_FORMAT " ]", 1414 INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value), 1415 INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value), 1416 INT64_RANGE_STEP (value)); 1417 } 1418 1419 static gboolean 1420 gst_value_deserialize_int64_range (GValue * dest, const gchar * s) 1421 { 1422 g_warning ("unimplemented"); 1423 return FALSE; 1424 } 1425 1426 /**************** 1427 * double range * 1428 ****************/ 1429 1430 static void 1431 gst_value_init_double_range (GValue * value) 1432 { 1433 value->data[0].v_double = 0; 1434 value->data[1].v_double = 0; 1435 } 1436 1437 static void 1438 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value) 1439 { 1440 dest_value->data[0].v_double = src_value->data[0].v_double; 1441 dest_value->data[1].v_double = src_value->data[1].v_double; 1442 } 1443 1444 static gchar * 1445 gst_value_collect_double_range (GValue * value, guint n_collect_values, 1446 GTypeCValue * collect_values, guint collect_flags) 1447 { 1448 if (n_collect_values != 2) 1449 return g_strdup_printf ("not enough value locations for `%s' passed", 1450 G_VALUE_TYPE_NAME (value)); 1451 if (collect_values[0].v_double >= collect_values[1].v_double) 1452 return g_strdup_printf ("range start is not smaller than end for `%s'", 1453 G_VALUE_TYPE_NAME (value)); 1454 1455 value->data[0].v_double = collect_values[0].v_double; 1456 value->data[1].v_double = collect_values[1].v_double; 1457 1458 return NULL; 1459 } 1460 1461 static gchar * 1462 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values, 1463 GTypeCValue * collect_values, guint collect_flags) 1464 { 1465 gdouble *double_range_start = collect_values[0].v_pointer; 1466 gdouble *double_range_end = collect_values[1].v_pointer; 1467 1468 if (!double_range_start) 1469 return g_strdup_printf ("start value location for `%s' passed as NULL", 1470 G_VALUE_TYPE_NAME (value)); 1471 if (!double_range_end) 1472 return g_strdup_printf ("end value location for `%s' passed as NULL", 1473 G_VALUE_TYPE_NAME (value)); 1474 1475 *double_range_start = value->data[0].v_double; 1476 *double_range_end = value->data[1].v_double; 1477 1478 return NULL; 1479 } 1480 1481 /** 1482 * gst_value_set_double_range: 1483 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE 1484 * @start: the start of the range 1485 * @end: the end of the range 1486 * 1487 * Sets @value to the range specified by @start and @end. 1488 */ 1489 void 1490 gst_value_set_double_range (GValue * value, gdouble start, gdouble end) 1491 { 1492 g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value)); 1493 g_return_if_fail (start < end); 1494 1495 value->data[0].v_double = start; 1496 value->data[1].v_double = end; 1497 } 1498 1499 /** 1500 * gst_value_get_double_range_min: 1501 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE 1502 * 1503 * Gets the minimum of the range specified by @value. 1504 * 1505 * Returns: the minimum of the range 1506 */ 1507 gdouble 1508 gst_value_get_double_range_min (const GValue * value) 1509 { 1510 g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0); 1511 1512 return value->data[0].v_double; 1513 } 1514 1515 /** 1516 * gst_value_get_double_range_max: 1517 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE 1518 * 1519 * Gets the maximum of the range specified by @value. 1520 * 1521 * Returns: the maximum of the range 1522 */ 1523 gdouble 1524 gst_value_get_double_range_max (const GValue * value) 1525 { 1526 g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0); 1527 1528 return value->data[1].v_double; 1529 } 1530 1531 static void 1532 gst_value_transform_double_range_string (const GValue * src_value, 1533 GValue * dest_value) 1534 { 1535 gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE]; 1536 1537 dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]", 1538 g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE, 1539 src_value->data[0].v_double), 1540 g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE, 1541 src_value->data[1].v_double)); 1542 } 1543 1544 static gint 1545 gst_value_compare_double_range (const GValue * value1, const GValue * value2) 1546 { 1547 if (value2->data[0].v_double == value1->data[0].v_double && 1548 value2->data[1].v_double == value1->data[1].v_double) 1549 return GST_VALUE_EQUAL; 1550 return GST_VALUE_UNORDERED; 1551 } 1552 1553 static gchar * 1554 gst_value_serialize_double_range (const GValue * value) 1555 { 1556 gchar d1[G_ASCII_DTOSTR_BUF_SIZE]; 1557 gchar d2[G_ASCII_DTOSTR_BUF_SIZE]; 1558 1559 g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double); 1560 g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double); 1561 return g_strdup_printf ("[ %s, %s ]", d1, d2); 1562 } 1563 1564 static gboolean 1565 gst_value_deserialize_double_range (GValue * dest, const gchar * s) 1566 { 1567 g_warning ("unimplemented"); 1568 return FALSE; 1569 } 1570 1571 /**************** 1572 * fraction range * 1573 ****************/ 1574 1575 static void 1576 gst_value_init_fraction_range (GValue * value) 1577 { 1578 GValue *vals; 1579 GType ftype; 1580 1581 ftype = GST_TYPE_FRACTION; 1582 1583 value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue)); 1584 g_value_init (&vals[0], ftype); 1585 g_value_init (&vals[1], ftype); 1586 } 1587 1588 static void 1589 gst_value_free_fraction_range (GValue * value) 1590 { 1591 GValue *vals = (GValue *) value->data[0].v_pointer; 1592 1593 if (vals != NULL) { 1594 /* we know the two values contain fractions without internal allocs */ 1595 /* g_value_unset (&vals[0]); */ 1596 /* g_value_unset (&vals[1]); */ 1597 g_slice_free1 (2 * sizeof (GValue), vals); 1598 value->data[0].v_pointer = NULL; 1599 } 1600 } 1601 1602 static void 1603 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value) 1604 { 1605 GValue *vals = (GValue *) dest_value->data[0].v_pointer; 1606 GValue *src_vals = (GValue *) src_value->data[0].v_pointer; 1607 1608 if (vals == NULL) { 1609 gst_value_init_fraction_range (dest_value); 1610 vals = dest_value->data[0].v_pointer; 1611 } 1612 if (src_vals != NULL) { 1613 g_value_copy (&src_vals[0], &vals[0]); 1614 g_value_copy (&src_vals[1], &vals[1]); 1615 } 1616 } 1617 1618 static gchar * 1619 gst_value_collect_fraction_range (GValue * value, guint n_collect_values, 1620 GTypeCValue * collect_values, guint collect_flags) 1621 { 1622 GValue *vals = (GValue *) value->data[0].v_pointer; 1623 1624 if (n_collect_values != 4) 1625 return g_strdup_printf ("not enough value locations for `%s' passed", 1626 G_VALUE_TYPE_NAME (value)); 1627 if (collect_values[1].v_int == 0) 1628 return g_strdup_printf ("passed '0' as first denominator for `%s'", 1629 G_VALUE_TYPE_NAME (value)); 1630 if (collect_values[3].v_int == 0) 1631 return g_strdup_printf ("passed '0' as second denominator for `%s'", 1632 G_VALUE_TYPE_NAME (value)); 1633 if (gst_util_fraction_compare (collect_values[0].v_int, 1634 collect_values[1].v_int, collect_values[2].v_int, 1635 collect_values[3].v_int) >= 0) 1636 return g_strdup_printf ("range start is not smaller than end for `%s'", 1637 G_VALUE_TYPE_NAME (value)); 1638 1639 if (vals == NULL) { 1640 gst_value_init_fraction_range (value); 1641 vals = value->data[0].v_pointer; 1642 } 1643 1644 gst_value_set_fraction (&vals[0], collect_values[0].v_int, 1645 collect_values[1].v_int); 1646 gst_value_set_fraction (&vals[1], collect_values[2].v_int, 1647 collect_values[3].v_int); 1648 1649 return NULL; 1650 } 1651 1652 static gchar * 1653 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values, 1654 GTypeCValue * collect_values, guint collect_flags) 1655 { 1656 gint i; 1657 gint *dest_values[4]; 1658 GValue *vals = (GValue *) value->data[0].v_pointer; 1659 1660 if (G_UNLIKELY (n_collect_values != 4)) 1661 return g_strdup_printf ("not enough value locations for `%s' passed", 1662 G_VALUE_TYPE_NAME (value)); 1663 1664 for (i = 0; i < 4; i++) { 1665 if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) { 1666 return g_strdup_printf ("value location for `%s' passed as NULL", 1667 G_VALUE_TYPE_NAME (value)); 1668 } 1669 dest_values[i] = collect_values[i].v_pointer; 1670 } 1671 1672 if (G_UNLIKELY (vals == NULL)) { 1673 return g_strdup_printf ("Uninitialised `%s' passed", 1674 G_VALUE_TYPE_NAME (value)); 1675 } 1676 1677 dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]); 1678 dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]); 1679 dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]); 1680 dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]); 1681 return NULL; 1682 } 1683 1684 /** 1685 * gst_value_set_fraction_range: 1686 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1687 * @start: the start of the range (a GST_TYPE_FRACTION GValue) 1688 * @end: the end of the range (a GST_TYPE_FRACTION GValue) 1689 * 1690 * Sets @value to the range specified by @start and @end. 1691 */ 1692 void 1693 gst_value_set_fraction_range (GValue * value, const GValue * start, 1694 const GValue * end) 1695 { 1696 GValue *vals; 1697 1698 g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value)); 1699 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start)); 1700 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end)); 1701 g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int, 1702 start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0); 1703 1704 vals = (GValue *) value->data[0].v_pointer; 1705 if (vals == NULL) { 1706 gst_value_init_fraction_range (value); 1707 vals = value->data[0].v_pointer; 1708 } 1709 g_value_copy (start, &vals[0]); 1710 g_value_copy (end, &vals[1]); 1711 } 1712 1713 /** 1714 * gst_value_set_fraction_range_full: 1715 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1716 * @numerator_start: the numerator start of the range 1717 * @denominator_start: the denominator start of the range 1718 * @numerator_end: the numerator end of the range 1719 * @denominator_end: the denominator end of the range 1720 * 1721 * Sets @value to the range specified by @numerator_start/@denominator_start 1722 * and @numerator_end/@denominator_end. 1723 */ 1724 void 1725 gst_value_set_fraction_range_full (GValue * value, 1726 gint numerator_start, gint denominator_start, 1727 gint numerator_end, gint denominator_end) 1728 { 1729 GValue start = { 0 }; 1730 GValue end = { 0 }; 1731 1732 g_return_if_fail (value != NULL); 1733 g_return_if_fail (denominator_start != 0); 1734 g_return_if_fail (denominator_end != 0); 1735 g_return_if_fail (gst_util_fraction_compare (numerator_start, 1736 denominator_start, numerator_end, denominator_end) < 0); 1737 1738 g_value_init (&start, GST_TYPE_FRACTION); 1739 g_value_init (&end, GST_TYPE_FRACTION); 1740 1741 gst_value_set_fraction (&start, numerator_start, denominator_start); 1742 gst_value_set_fraction (&end, numerator_end, denominator_end); 1743 gst_value_set_fraction_range (value, &start, &end); 1744 1745 /* we know the two values contain fractions without internal allocs */ 1746 /* g_value_unset (&start); */ 1747 /* g_value_unset (&end); */ 1748 } 1749 1750 /* FIXME 2.0: Don't leak the internal representation of fraction 1751 * ranges but instead return the numerator and denominator 1752 * separately. 1753 * This would allow to store fraction ranges as 1754 * data[0] = (min_n << 32) | (min_d) 1755 * data[1] = (max_n << 32) | (max_d) 1756 * without requiring an additional allocation for each value. 1757 */ 1758 1759 /** 1760 * gst_value_get_fraction_range_min: 1761 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1762 * 1763 * Gets the minimum of the range specified by @value. 1764 * 1765 * Returns: the minimum of the range 1766 */ 1767 const GValue * 1768 gst_value_get_fraction_range_min (const GValue * value) 1769 { 1770 GValue *vals; 1771 1772 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL); 1773 1774 vals = (GValue *) value->data[0].v_pointer; 1775 if (vals != NULL) { 1776 return &vals[0]; 1777 } 1778 1779 return NULL; 1780 } 1781 1782 /** 1783 * gst_value_get_fraction_range_max: 1784 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1785 * 1786 * Gets the maximum of the range specified by @value. 1787 * 1788 * Returns: the maximum of the range 1789 */ 1790 const GValue * 1791 gst_value_get_fraction_range_max (const GValue * value) 1792 { 1793 GValue *vals; 1794 1795 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL); 1796 1797 vals = (GValue *) value->data[0].v_pointer; 1798 if (vals != NULL) { 1799 return &vals[1]; 1800 } 1801 1802 return NULL; 1803 } 1804 1805 static gchar * 1806 gst_value_serialize_fraction_range (const GValue * value) 1807 { 1808 GValue *vals = (GValue *) value->data[0].v_pointer; 1809 gchar *retval; 1810 1811 if (vals == NULL) { 1812 retval = g_strdup ("[ 0/1, 0/1 ]"); 1813 } else { 1814 gchar *start, *end; 1815 1816 start = gst_value_serialize_fraction (&vals[0]); 1817 end = gst_value_serialize_fraction (&vals[1]); 1818 1819 retval = g_strdup_printf ("[ %s, %s ]", start, end); 1820 g_free (start); 1821 g_free (end); 1822 } 1823 1824 return retval; 1825 } 1826 1827 static void 1828 gst_value_transform_fraction_range_string (const GValue * src_value, 1829 GValue * dest_value) 1830 { 1831 dest_value->data[0].v_pointer = 1832 gst_value_serialize_fraction_range (src_value); 1833 } 1834 1835 static gint 1836 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2) 1837 { 1838 GValue *vals1, *vals2; 1839 GstValueCompareFunc compare; 1840 1841 if (value2->data[0].v_pointer == value1->data[0].v_pointer) 1842 return GST_VALUE_EQUAL; /* Only possible if both are NULL */ 1843 1844 if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL) 1845 return GST_VALUE_UNORDERED; 1846 1847 vals1 = (GValue *) value1->data[0].v_pointer; 1848 vals2 = (GValue *) value2->data[0].v_pointer; 1849 if ((compare = gst_value_get_compare_func (&vals1[0]))) { 1850 if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) == 1851 GST_VALUE_EQUAL && 1852 gst_value_compare_with_func (&vals1[1], &vals2[1], compare) == 1853 GST_VALUE_EQUAL) 1854 return GST_VALUE_EQUAL; 1855 } 1856 return GST_VALUE_UNORDERED; 1857 } 1858 1859 static gboolean 1860 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s) 1861 { 1862 g_warning ("unimplemented"); 1863 return FALSE; 1864 } 1865 1866 /*********** 1867 * GstCaps * 1868 ***********/ 1869 1870 /** 1871 * gst_value_set_caps: 1872 * @value: a GValue initialized to GST_TYPE_CAPS 1873 * @caps: (transfer none): the caps to set the value to 1874 * 1875 * Sets the contents of @value to @caps. A reference to the 1876 * provided @caps will be taken by the @value. 1877 */ 1878 void 1879 gst_value_set_caps (GValue * value, const GstCaps * caps) 1880 { 1881 g_return_if_fail (G_IS_VALUE (value)); 1882 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS); 1883 g_return_if_fail (caps == NULL || GST_IS_CAPS (caps)); 1884 1885 g_value_set_boxed (value, caps); 1886 } 1887 1888 /** 1889 * gst_value_get_caps: 1890 * @value: a GValue initialized to GST_TYPE_CAPS 1891 * 1892 * Gets the contents of @value. The reference count of the returned 1893 * #GstCaps will not be modified, therefore the caller must take one 1894 * before getting rid of the @value. 1895 * 1896 * Returns: (transfer none): the contents of @value 1897 */ 1898 const GstCaps * 1899 gst_value_get_caps (const GValue * value) 1900 { 1901 g_return_val_if_fail (G_IS_VALUE (value), NULL); 1902 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL); 1903 1904 return (GstCaps *) g_value_get_boxed (value); 1905 } 1906 1907 static gint 1908 gst_value_compare_caps (const GValue * value1, const GValue * value2) 1909 { 1910 GstCaps *caps1 = GST_CAPS (gst_value_get_caps (value1)); 1911 GstCaps *caps2 = GST_CAPS (gst_value_get_caps (value2)); 1912 1913 if (gst_caps_is_equal (caps1, caps2)) 1914 return GST_VALUE_EQUAL; 1915 return GST_VALUE_UNORDERED; 1916 } 1917 1918 static gchar * 1919 gst_value_serialize_caps (const GValue * value) 1920 { 1921 GstCaps *caps = g_value_get_boxed (value); 1922 return gst_string_take_and_wrap (gst_caps_to_string (caps)); 1923 } 1924 1925 static gboolean 1926 gst_value_deserialize_caps (GValue * dest, const gchar * s) 1927 { 1928 GstCaps *caps; 1929 1930 if (*s != '"') { 1931 caps = gst_caps_from_string (s); 1932 } else { 1933 gchar *str = gst_string_unwrap (s); 1934 1935 if (G_UNLIKELY (!str)) 1936 return FALSE; 1937 1938 caps = gst_caps_from_string (str); 1939 g_free (str); 1940 } 1941 1942 if (caps) { 1943 g_value_take_boxed (dest, caps); 1944 return TRUE; 1945 } 1946 return FALSE; 1947 } 1948 1949 /************** 1950 * GstSegment * 1951 **************/ 1952 1953 static gchar * 1954 gst_value_serialize_segment_internal (const GValue * value, gboolean escape) 1955 { 1956 GstSegment *seg = g_value_get_boxed (value); 1957 gchar *t, *res; 1958 GstStructure *s; 1959 1960 s = gst_structure_new ("GstSegment", 1961 "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags, 1962 "rate", G_TYPE_DOUBLE, seg->rate, 1963 "applied-rate", G_TYPE_DOUBLE, seg->applied_rate, 1964 "format", GST_TYPE_FORMAT, seg->format, 1965 "base", G_TYPE_UINT64, seg->base, 1966 "offset", G_TYPE_UINT64, seg->offset, 1967 "start", G_TYPE_UINT64, seg->start, 1968 "stop", G_TYPE_UINT64, seg->stop, 1969 "time", G_TYPE_UINT64, seg->time, 1970 "position", G_TYPE_UINT64, seg->position, 1971 "duration", G_TYPE_UINT64, seg->duration, NULL); 1972 t = gst_structure_to_string (s); 1973 if (escape) { 1974 res = g_strdup_printf ("\"%s\"", t); 1975 g_free (t); 1976 } else { 1977 res = t; 1978 } 1979 gst_structure_free (s); 1980 1981 return res; 1982 } 1983 1984 static gchar * 1985 gst_value_serialize_segment (const GValue * value) 1986 { 1987 return gst_value_serialize_segment_internal (value, TRUE); 1988 } 1989 1990 static gboolean 1991 gst_value_deserialize_segment (GValue * dest, const gchar * s) 1992 { 1993 GstStructure *str; 1994 GstSegment seg; 1995 gboolean res; 1996 1997 str = gst_structure_from_string (s, NULL); 1998 if (str == NULL) 1999 return FALSE; 2000 2001 res = gst_structure_get (str, 2002 "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags, 2003 "rate", G_TYPE_DOUBLE, &seg.rate, 2004 "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate, 2005 "format", GST_TYPE_FORMAT, &seg.format, 2006 "base", G_TYPE_UINT64, &seg.base, 2007 "offset", G_TYPE_UINT64, &seg.offset, 2008 "start", G_TYPE_UINT64, &seg.start, 2009 "stop", G_TYPE_UINT64, &seg.stop, 2010 "time", G_TYPE_UINT64, &seg.time, 2011 "position", G_TYPE_UINT64, &seg.position, 2012 "duration", G_TYPE_UINT64, &seg.duration, NULL); 2013 gst_structure_free (str); 2014 2015 if (res) 2016 g_value_set_boxed (dest, &seg); 2017 2018 return res; 2019 } 2020 2021 /**************** 2022 * GstStructure * 2023 ****************/ 2024 2025 /** 2026 * gst_value_set_structure: 2027 * @value: a GValue initialized to GST_TYPE_STRUCTURE 2028 * @structure: the structure to set the value to 2029 * 2030 * Sets the contents of @value to @structure. The actual 2031 */ 2032 void 2033 gst_value_set_structure (GValue * value, const GstStructure * structure) 2034 { 2035 g_return_if_fail (G_IS_VALUE (value)); 2036 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE); 2037 g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure)); 2038 2039 g_value_set_boxed (value, structure); 2040 } 2041 2042 /** 2043 * gst_value_get_structure: 2044 * @value: a GValue initialized to GST_TYPE_STRUCTURE 2045 * 2046 * Gets the contents of @value. 2047 * 2048 * Returns: (transfer none): the contents of @value 2049 */ 2050 const GstStructure * 2051 gst_value_get_structure (const GValue * value) 2052 { 2053 g_return_val_if_fail (G_IS_VALUE (value), NULL); 2054 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL); 2055 2056 return (GstStructure *) g_value_get_boxed (value); 2057 } 2058 2059 static gchar * 2060 gst_value_serialize_structure (const GValue * value) 2061 { 2062 GstStructure *structure = g_value_get_boxed (value); 2063 2064 return gst_string_take_and_wrap (gst_structure_to_string (structure)); 2065 } 2066 2067 static gboolean 2068 gst_value_deserialize_structure (GValue * dest, const gchar * s) 2069 { 2070 GstStructure *structure; 2071 2072 if (*s != '"') { 2073 structure = gst_structure_from_string (s, NULL); 2074 } else { 2075 gchar *str = gst_string_unwrap (s); 2076 2077 if (G_UNLIKELY (!str)) 2078 return FALSE; 2079 2080 structure = gst_structure_from_string (str, NULL); 2081 g_free (str); 2082 } 2083 2084 if (G_LIKELY (structure)) { 2085 g_value_take_boxed (dest, structure); 2086 return TRUE; 2087 } 2088 return FALSE; 2089 } 2090 2091 /******************* 2092 * GstCapsFeatures * 2093 *******************/ 2094 2095 /** 2096 * gst_value_set_caps_features: 2097 * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES 2098 * @features: the features to set the value to 2099 * 2100 * Sets the contents of @value to @features. 2101 */ 2102 void 2103 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features) 2104 { 2105 g_return_if_fail (G_IS_VALUE (value)); 2106 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES); 2107 g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features)); 2108 2109 g_value_set_boxed (value, features); 2110 } 2111 2112 /** 2113 * gst_value_get_caps_features: 2114 * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES 2115 * 2116 * Gets the contents of @value. 2117 * 2118 * Returns: (transfer none): the contents of @value 2119 */ 2120 const GstCapsFeatures * 2121 gst_value_get_caps_features (const GValue * value) 2122 { 2123 g_return_val_if_fail (G_IS_VALUE (value), NULL); 2124 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL); 2125 2126 return (GstCapsFeatures *) g_value_get_boxed (value); 2127 } 2128 2129 static gchar * 2130 gst_value_serialize_caps_features (const GValue * value) 2131 { 2132 GstCapsFeatures *features = g_value_get_boxed (value); 2133 2134 return gst_string_take_and_wrap (gst_caps_features_to_string (features)); 2135 } 2136 2137 static gboolean 2138 gst_value_deserialize_caps_features (GValue * dest, const gchar * s) 2139 { 2140 GstCapsFeatures *features; 2141 2142 if (*s != '"') { 2143 features = gst_caps_features_from_string (s); 2144 } else { 2145 gchar *str = gst_string_unwrap (s); 2146 2147 if (G_UNLIKELY (!str)) 2148 return FALSE; 2149 2150 features = gst_caps_features_from_string (str); 2151 g_free (str); 2152 } 2153 2154 if (G_LIKELY (features)) { 2155 g_value_take_boxed (dest, features); 2156 return TRUE; 2157 } 2158 return FALSE; 2159 } 2160 2161 /************** 2162 * GstTagList * 2163 **************/ 2164 2165 static gboolean 2166 gst_value_deserialize_tag_list (GValue * dest, const gchar * s) 2167 { 2168 GstTagList *taglist; 2169 2170 if (*s != '"') { 2171 taglist = gst_tag_list_new_from_string (s); 2172 } else { 2173 gchar *str = gst_string_unwrap (s); 2174 2175 if (G_UNLIKELY (!str)) 2176 return FALSE; 2177 2178 taglist = gst_tag_list_new_from_string (str); 2179 g_free (str); 2180 } 2181 2182 if (G_LIKELY (taglist != NULL)) { 2183 g_value_take_boxed (dest, taglist); 2184 return TRUE; 2185 } 2186 return FALSE; 2187 } 2188 2189 static gchar * 2190 gst_value_serialize_tag_list (const GValue * value) 2191 { 2192 GstTagList *taglist = g_value_get_boxed (value); 2193 2194 return gst_string_take_and_wrap (gst_tag_list_to_string (taglist)); 2195 } 2196 2197 2198 /************* 2199 * GstBuffer * 2200 *************/ 2201 2202 static gint 2203 compare_buffer (GstBuffer * buf1, GstBuffer * buf2) 2204 { 2205 gsize size1, size2; 2206 GstMapInfo info1, info2; 2207 gint result, mret; 2208 2209 if (buf1 == buf2) 2210 return GST_VALUE_EQUAL; 2211 2212 size1 = gst_buffer_get_size (buf1); 2213 size2 = gst_buffer_get_size (buf2); 2214 2215 if (size1 != size2) 2216 return GST_VALUE_UNORDERED; 2217 2218 if (size1 == 0) 2219 return GST_VALUE_EQUAL; 2220 2221 if (!gst_buffer_map (buf1, &info1, GST_MAP_READ)) 2222 return GST_VALUE_UNORDERED; 2223 2224 if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) { 2225 gst_buffer_unmap (buf1, &info1); 2226 return GST_VALUE_UNORDERED; 2227 } 2228 2229 mret = memcmp (info1.data, info2.data, info1.size); 2230 if (mret == 0) 2231 result = GST_VALUE_EQUAL; 2232 else if (mret < 0) 2233 result = GST_VALUE_LESS_THAN; 2234 else 2235 result = GST_VALUE_GREATER_THAN; 2236 2237 gst_buffer_unmap (buf1, &info1); 2238 gst_buffer_unmap (buf2, &info2); 2239 2240 return result; 2241 } 2242 2243 static gint 2244 gst_value_compare_buffer (const GValue * value1, const GValue * value2) 2245 { 2246 GstBuffer *buf1 = gst_value_get_buffer (value1); 2247 GstBuffer *buf2 = gst_value_get_buffer (value2); 2248 2249 return compare_buffer (buf1, buf2); 2250 } 2251 2252 static gchar * 2253 gst_value_serialize_buffer (const GValue * value) 2254 { 2255 GstMapInfo info; 2256 guint8 *data; 2257 gint i; 2258 gchar *string; 2259 GstBuffer *buffer; 2260 2261 buffer = gst_value_get_buffer (value); 2262 if (buffer == NULL) 2263 return NULL; 2264 2265 if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) 2266 return NULL; 2267 2268 data = info.data; 2269 2270 string = g_malloc (info.size * 2 + 1); 2271 for (i = 0; i < info.size; i++) { 2272 sprintf (string + i * 2, "%02x", data[i]); 2273 } 2274 string[info.size * 2] = 0; 2275 2276 gst_buffer_unmap (buffer, &info); 2277 2278 return string; 2279 } 2280 2281 static gboolean 2282 gst_value_deserialize_buffer (GValue * dest, const gchar * s) 2283 { 2284 GstBuffer *buffer; 2285 gint len; 2286 gchar ts[3]; 2287 GstMapInfo info; 2288 guint8 *data; 2289 gint i; 2290 2291 len = strlen (s); 2292 if (len & 1) 2293 goto wrong_length; 2294 2295 buffer = gst_buffer_new_allocate (NULL, len / 2, NULL); 2296 if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE)) 2297 goto map_failed; 2298 data = info.data; 2299 2300 for (i = 0; i < len / 2; i++) { 2301 if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) 2302 goto wrong_char; 2303 2304 ts[0] = s[i * 2 + 0]; 2305 ts[1] = s[i * 2 + 1]; 2306 ts[2] = 0; 2307 2308 data[i] = (guint8) strtoul (ts, NULL, 16); 2309 } 2310 gst_buffer_unmap (buffer, &info); 2311 2312 gst_value_take_buffer (dest, buffer); 2313 2314 return TRUE; 2315 2316 /* ERRORS */ 2317 wrong_length: 2318 { 2319 return FALSE; 2320 } 2321 map_failed: 2322 { 2323 return FALSE; 2324 } 2325 wrong_char: 2326 { 2327 gst_buffer_unref (buffer); 2328 gst_buffer_unmap (buffer, &info); 2329 return FALSE; 2330 } 2331 } 2332 2333 /************* 2334 * GstSample * 2335 *************/ 2336 2337 /* This function is mostly used for comparing image/buffer tags in taglists */ 2338 static gint 2339 gst_value_compare_sample (const GValue * value1, const GValue * value2) 2340 { 2341 GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1)); 2342 GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2)); 2343 2344 /* FIXME: should we take into account anything else such as caps? */ 2345 return compare_buffer (buf1, buf2); 2346 } 2347 2348 static gchar * 2349 gst_value_serialize_sample (const GValue * value) 2350 { 2351 const GstStructure *info_structure; 2352 GstSegment *segment; 2353 GstBuffer *buffer; 2354 GstCaps *caps; 2355 GstSample *sample; 2356 GValue val = { 0, }; 2357 gchar *info_str, *caps_str, *tmp; 2358 gchar *buf_str, *seg_str, *s; 2359 2360 sample = g_value_get_boxed (value); 2361 2362 buffer = gst_sample_get_buffer (sample); 2363 if (buffer) { 2364 g_value_init (&val, GST_TYPE_BUFFER); 2365 g_value_set_boxed (&val, buffer); 2366 buf_str = gst_value_serialize_buffer (&val); 2367 g_value_unset (&val); 2368 } else { 2369 buf_str = g_strdup ("None"); 2370 } 2371 2372 caps = gst_sample_get_caps (sample); 2373 if (caps) { 2374 tmp = gst_caps_to_string (caps); 2375 caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1); 2376 g_strdelimit (caps_str, "=", '_'); 2377 g_free (tmp); 2378 } else { 2379 caps_str = g_strdup ("None"); 2380 } 2381 2382 segment = gst_sample_get_segment (sample); 2383 if (segment) { 2384 g_value_init (&val, GST_TYPE_SEGMENT); 2385 g_value_set_boxed (&val, segment); 2386 tmp = gst_value_serialize_segment_internal (&val, FALSE); 2387 seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1); 2388 g_strdelimit (seg_str, "=", '_'); 2389 g_free (tmp); 2390 g_value_unset (&val); 2391 } else { 2392 seg_str = g_strdup ("None"); 2393 } 2394 2395 info_structure = gst_sample_get_info (sample); 2396 if (info_structure) { 2397 tmp = gst_structure_to_string (info_structure); 2398 info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1); 2399 g_strdelimit (info_str, "=", '_'); 2400 g_free (tmp); 2401 } else { 2402 info_str = g_strdup ("None"); 2403 } 2404 2405 s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL); 2406 g_free (buf_str); 2407 g_free (caps_str); 2408 g_free (seg_str); 2409 g_free (info_str); 2410 2411 return s; 2412 } 2413 2414 static gboolean 2415 gst_value_deserialize_sample (GValue * dest, const gchar * s) 2416 { 2417 GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT; 2418 GstStructure *info; 2419 GstSample *sample; 2420 GstCaps *caps; 2421 gboolean ret = FALSE; 2422 gchar **fields; 2423 gsize outlen; 2424 gint len; 2425 2426 GST_TRACE ("deserialize '%s'", s); 2427 2428 fields = g_strsplit (s, ":", -1); 2429 len = g_strv_length (fields); 2430 if (len != 4) 2431 goto wrong_length; 2432 2433 g_value_init (&bval, GST_TYPE_BUFFER); 2434 g_value_init (&sval, GST_TYPE_SEGMENT); 2435 2436 if (!gst_value_deserialize_buffer (&bval, fields[0])) 2437 goto fail; 2438 2439 if (strcmp (fields[1], "None") != 0) { 2440 g_strdelimit (fields[1], "_", '='); 2441 g_base64_decode_inplace (fields[1], &outlen); 2442 GST_TRACE ("caps : %s", fields[1]); 2443 caps = gst_caps_from_string (fields[1]); 2444 if (caps == NULL) 2445 goto fail; 2446 } else { 2447 caps = NULL; 2448 } 2449 2450 if (strcmp (fields[2], "None") != 0) { 2451 g_strdelimit (fields[2], "_", '='); 2452 g_base64_decode_inplace (fields[2], &outlen); 2453 GST_TRACE ("segment : %s", fields[2]); 2454 if (!gst_value_deserialize_segment (&sval, fields[2])) 2455 goto fail; 2456 } 2457 2458 if (strcmp (fields[3], "None") != 0) { 2459 g_strdelimit (fields[3], "_", '='); 2460 g_base64_decode_inplace (fields[3], &outlen); 2461 GST_TRACE ("info : %s", fields[3]); 2462 info = gst_structure_from_string (fields[3], NULL); 2463 if (info == NULL) 2464 goto fail; 2465 } else { 2466 info = NULL; 2467 } 2468 2469 sample = gst_sample_new (gst_value_get_buffer (&bval), caps, 2470 g_value_get_boxed (&sval), info); 2471 2472 g_value_take_boxed (dest, sample); 2473 2474 if (caps) 2475 gst_caps_unref (caps); 2476 2477 ret = TRUE; 2478 2479 fail: 2480 2481 g_value_unset (&bval); 2482 g_value_unset (&sval); 2483 2484 wrong_length: 2485 2486 g_strfreev (fields); 2487 2488 return ret; 2489 } 2490 2491 /*********** 2492 * boolean * 2493 ***********/ 2494 2495 static gint 2496 gst_value_compare_boolean (const GValue * value1, const GValue * value2) 2497 { 2498 if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0)) 2499 return GST_VALUE_EQUAL; 2500 return GST_VALUE_UNORDERED; 2501 } 2502 2503 static gchar * 2504 gst_value_serialize_boolean (const GValue * value) 2505 { 2506 if (value->data[0].v_int) { 2507 return g_strdup ("true"); 2508 } 2509 return g_strdup ("false"); 2510 } 2511 2512 static gboolean 2513 gst_value_deserialize_boolean (GValue * dest, const gchar * s) 2514 { 2515 gboolean ret = FALSE; 2516 2517 if (g_ascii_strcasecmp (s, "true") == 0 || 2518 g_ascii_strcasecmp (s, "yes") == 0 || 2519 g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) { 2520 g_value_set_boolean (dest, TRUE); 2521 ret = TRUE; 2522 } else if (g_ascii_strcasecmp (s, "false") == 0 || 2523 g_ascii_strcasecmp (s, "no") == 0 || 2524 g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) { 2525 g_value_set_boolean (dest, FALSE); 2526 ret = TRUE; 2527 } 2528 2529 return ret; 2530 } 2531 2532 #define CREATE_SERIALIZATION_START(_type,_macro) \ 2533 static gint \ 2534 gst_value_compare_ ## _type \ 2535 (const GValue * value1, const GValue * value2) \ 2536 { \ 2537 g ## _type val1 = g_value_get_ ## _type (value1); \ 2538 g ## _type val2 = g_value_get_ ## _type (value2); \ 2539 if (val1 > val2) \ 2540 return GST_VALUE_GREATER_THAN; \ 2541 if (val1 < val2) \ 2542 return GST_VALUE_LESS_THAN; \ 2543 return GST_VALUE_EQUAL; \ 2544 } \ 2545 \ 2546 static gchar * \ 2547 gst_value_serialize_ ## _type (const GValue * value) \ 2548 { \ 2549 GValue val = { 0, }; \ 2550 g_value_init (&val, G_TYPE_STRING); \ 2551 if (!g_value_transform (value, &val)) \ 2552 g_assert_not_reached (); \ 2553 /* NO_COPY_MADNESS!!! */ \ 2554 return (char *) g_value_get_string (&val); \ 2555 } 2556 2557 /* deserialize the given s into to as a gint64. 2558 * check if the result is actually storeable in the given size number of 2559 * bytes. 2560 */ 2561 static gboolean 2562 gst_value_deserialize_int_helper (gint64 * to, const gchar * s, 2563 gint64 min, gint64 max, gint size) 2564 { 2565 gboolean ret = FALSE; 2566 gchar *end; 2567 guint64 mask = ~0; 2568 2569 errno = 0; 2570 *to = g_ascii_strtoull (s, &end, 0); 2571 /* a range error is a definitive no-no */ 2572 if (errno == ERANGE) { 2573 return FALSE; 2574 } 2575 2576 if (*end == 0) { 2577 ret = TRUE; 2578 } else { 2579 if (g_ascii_strcasecmp (s, "little_endian") == 0) { 2580 *to = G_LITTLE_ENDIAN; 2581 ret = TRUE; 2582 } else if (g_ascii_strcasecmp (s, "big_endian") == 0) { 2583 *to = G_BIG_ENDIAN; 2584 ret = TRUE; 2585 } else if (g_ascii_strcasecmp (s, "byte_order") == 0) { 2586 *to = G_BYTE_ORDER; 2587 ret = TRUE; 2588 } else if (g_ascii_strcasecmp (s, "min") == 0) { 2589 *to = min; 2590 ret = TRUE; 2591 } else if (g_ascii_strcasecmp (s, "max") == 0) { 2592 *to = max; 2593 ret = TRUE; 2594 } 2595 } 2596 if (ret) { 2597 /* by definition, a gint64 fits into a gint64; so ignore those */ 2598 if (size != sizeof (mask)) { 2599 if (*to >= 0) { 2600 /* for positive numbers, we create a mask of 1's outside of the range 2601 * and 0's inside the range. An and will thus keep only 1 bits 2602 * outside of the range */ 2603 mask <<= (size * 8); 2604 if ((mask & *to) != 0) { 2605 ret = FALSE; 2606 } 2607 } else { 2608 /* for negative numbers, we do a 2's complement version */ 2609 mask <<= ((size * 8) - 1); 2610 if ((mask & *to) != mask) { 2611 ret = FALSE; 2612 } 2613 } 2614 } 2615 } 2616 return ret; 2617 } 2618 2619 #define CREATE_SERIALIZATION(_type,_macro) \ 2620 CREATE_SERIALIZATION_START(_type,_macro) \ 2621 \ 2622 static gboolean \ 2623 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s) \ 2624 { \ 2625 gint64 x; \ 2626 \ 2627 if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro, \ 2628 G_MAX ## _macro, sizeof (g ## _type))) { \ 2629 g_value_set_ ## _type (dest, /*(g ## _type)*/ x); \ 2630 return TRUE; \ 2631 } else { \ 2632 return FALSE; \ 2633 } \ 2634 } 2635 2636 #define CREATE_USERIALIZATION(_type,_macro) \ 2637 CREATE_SERIALIZATION_START(_type,_macro) \ 2638 \ 2639 static gboolean \ 2640 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s) \ 2641 { \ 2642 gint64 x; \ 2643 gchar *end; \ 2644 gboolean ret = FALSE; \ 2645 \ 2646 errno = 0; \ 2647 x = g_ascii_strtoull (s, &end, 0); \ 2648 /* a range error is a definitive no-no */ \ 2649 if (errno == ERANGE) { \ 2650 return FALSE; \ 2651 } \ 2652 /* the cast ensures the range check later on makes sense */ \ 2653 x = (g ## _type) x; \ 2654 if (*end == 0) { \ 2655 ret = TRUE; \ 2656 } else { \ 2657 if (g_ascii_strcasecmp (s, "little_endian") == 0) { \ 2658 x = G_LITTLE_ENDIAN; \ 2659 ret = TRUE; \ 2660 } else if (g_ascii_strcasecmp (s, "big_endian") == 0) { \ 2661 x = G_BIG_ENDIAN; \ 2662 ret = TRUE; \ 2663 } else if (g_ascii_strcasecmp (s, "byte_order") == 0) { \ 2664 x = G_BYTE_ORDER; \ 2665 ret = TRUE; \ 2666 } else if (g_ascii_strcasecmp (s, "min") == 0) { \ 2667 x = 0; \ 2668 ret = TRUE; \ 2669 } else if (g_ascii_strcasecmp (s, "max") == 0) { \ 2670 x = G_MAX ## _macro; \ 2671 ret = TRUE; \ 2672 } \ 2673 } \ 2674 if (ret) { \ 2675 if (x > G_MAX ## _macro) { \ 2676 ret = FALSE; \ 2677 } else { \ 2678 g_value_set_ ## _type (dest, x); \ 2679 } \ 2680 } \ 2681 return ret; \ 2682 } 2683 2684 #define REGISTER_SERIALIZATION(_gtype, _type) \ 2685 G_STMT_START { \ 2686 static const GstValueTable gst_value = { \ 2687 _gtype, \ 2688 gst_value_compare_ ## _type, \ 2689 gst_value_serialize_ ## _type, \ 2690 gst_value_deserialize_ ## _type, \ 2691 }; \ 2692 \ 2693 gst_value_register (&gst_value); \ 2694 } G_STMT_END 2695 2696 CREATE_SERIALIZATION (int, INT); 2697 CREATE_SERIALIZATION (int64, INT64); 2698 CREATE_SERIALIZATION (long, LONG); 2699 2700 CREATE_USERIALIZATION (uint, UINT); 2701 CREATE_USERIALIZATION (uint64, UINT64); 2702 CREATE_USERIALIZATION (ulong, ULONG); 2703 2704 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */ 2705 #ifndef G_MAXUCHAR 2706 #define G_MAXUCHAR 255 2707 #endif 2708 CREATE_USERIALIZATION (uchar, UCHAR); 2709 2710 /********** 2711 * double * 2712 **********/ 2713 static gint 2714 gst_value_compare_double (const GValue * value1, const GValue * value2) 2715 { 2716 if (value1->data[0].v_double > value2->data[0].v_double) 2717 return GST_VALUE_GREATER_THAN; 2718 if (value1->data[0].v_double < value2->data[0].v_double) 2719 return GST_VALUE_LESS_THAN; 2720 if (value1->data[0].v_double == value2->data[0].v_double) 2721 return GST_VALUE_EQUAL; 2722 return GST_VALUE_UNORDERED; 2723 } 2724 2725 static gchar * 2726 gst_value_serialize_double (const GValue * value) 2727 { 2728 gchar d[G_ASCII_DTOSTR_BUF_SIZE]; 2729 2730 g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double); 2731 return g_strdup (d); 2732 } 2733 2734 static gboolean 2735 gst_value_deserialize_double (GValue * dest, const gchar * s) 2736 { 2737 gdouble x; 2738 gboolean ret = FALSE; 2739 gchar *end; 2740 2741 x = g_ascii_strtod (s, &end); 2742 if (*end == 0) { 2743 ret = TRUE; 2744 } else { 2745 if (g_ascii_strcasecmp (s, "min") == 0) { 2746 x = -G_MAXDOUBLE; 2747 ret = TRUE; 2748 } else if (g_ascii_strcasecmp (s, "max") == 0) { 2749 x = G_MAXDOUBLE; 2750 ret = TRUE; 2751 } 2752 } 2753 if (ret) { 2754 g_value_set_double (dest, x); 2755 } 2756 return ret; 2757 } 2758 2759 /********* 2760 * float * 2761 *********/ 2762 2763 static gint 2764 gst_value_compare_float (const GValue * value1, const GValue * value2) 2765 { 2766 if (value1->data[0].v_float > value2->data[0].v_float) 2767 return GST_VALUE_GREATER_THAN; 2768 if (value1->data[0].v_float < value2->data[0].v_float) 2769 return GST_VALUE_LESS_THAN; 2770 if (value1->data[0].v_float == value2->data[0].v_float) 2771 return GST_VALUE_EQUAL; 2772 return GST_VALUE_UNORDERED; 2773 } 2774 2775 static gchar * 2776 gst_value_serialize_float (const GValue * value) 2777 { 2778 gchar d[G_ASCII_DTOSTR_BUF_SIZE]; 2779 2780 g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float); 2781 return g_strdup (d); 2782 } 2783 2784 static gboolean 2785 gst_value_deserialize_float (GValue * dest, const gchar * s) 2786 { 2787 gdouble x; 2788 gboolean ret = FALSE; 2789 gchar *end; 2790 2791 x = g_ascii_strtod (s, &end); 2792 if (*end == 0) { 2793 ret = TRUE; 2794 } else { 2795 if (g_ascii_strcasecmp (s, "min") == 0) { 2796 x = -G_MAXFLOAT; 2797 ret = TRUE; 2798 } else if (g_ascii_strcasecmp (s, "max") == 0) { 2799 x = G_MAXFLOAT; 2800 ret = TRUE; 2801 } 2802 } 2803 if (x > G_MAXFLOAT || x < -G_MAXFLOAT) 2804 ret = FALSE; 2805 if (ret) { 2806 g_value_set_float (dest, (float) x); 2807 } 2808 return ret; 2809 } 2810 2811 /********** 2812 * string * 2813 **********/ 2814 2815 static gint 2816 gst_value_compare_string (const GValue * value1, const GValue * value2) 2817 { 2818 if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) { 2819 /* if only one is NULL, no match - otherwise both NULL == EQUAL */ 2820 if (value1->data[0].v_pointer != value2->data[0].v_pointer) 2821 return GST_VALUE_UNORDERED; 2822 } else { 2823 gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer); 2824 2825 if (x < 0) 2826 return GST_VALUE_LESS_THAN; 2827 if (x > 0) 2828 return GST_VALUE_GREATER_THAN; 2829 } 2830 2831 return GST_VALUE_EQUAL; 2832 } 2833 2834 static gint 2835 gst_string_measure_wrapping (const gchar * s) 2836 { 2837 gint len; 2838 gboolean wrap = FALSE; 2839 2840 if (G_UNLIKELY (s == NULL)) 2841 return -1; 2842 2843 /* Special case: the actual string NULL needs wrapping */ 2844 if (G_UNLIKELY (strcmp (s, "NULL") == 0)) 2845 return 4; 2846 2847 len = 0; 2848 while (*s) { 2849 if (GST_ASCII_IS_STRING (*s)) { 2850 len++; 2851 } else if (*s < 0x20 || *s >= 0x7f) { 2852 wrap = TRUE; 2853 len += 4; 2854 } else { 2855 wrap = TRUE; 2856 len += 2; 2857 } 2858 s++; 2859 } 2860 2861 /* Wrap the string if we found something that needs 2862 * wrapping, or the empty string (len == 0) */ 2863 return (wrap || len == 0) ? len : -1; 2864 } 2865 2866 static gchar * 2867 gst_string_wrap_inner (const gchar * s, gint len) 2868 { 2869 gchar *d, *e; 2870 2871 e = d = g_malloc (len + 3); 2872 2873 *e++ = '\"'; 2874 while (*s) { 2875 if (GST_ASCII_IS_STRING (*s)) { 2876 *e++ = *s++; 2877 } else if (*s < 0x20 || *s >= 0x7f) { 2878 *e++ = '\\'; 2879 *e++ = '0' + ((*(guchar *) s) >> 6); 2880 *e++ = '0' + (((*s) >> 3) & 0x7); 2881 *e++ = '0' + ((*s++) & 0x7); 2882 } else { 2883 *e++ = '\\'; 2884 *e++ = *s++; 2885 } 2886 } 2887 *e++ = '\"'; 2888 *e = 0; 2889 2890 g_assert (e - d <= len + 3); 2891 return d; 2892 } 2893 2894 /* Do string wrapping/escaping */ 2895 static gchar * 2896 gst_string_wrap (const gchar * s) 2897 { 2898 gint len = gst_string_measure_wrapping (s); 2899 2900 if (G_LIKELY (len < 0)) 2901 return g_strdup (s); 2902 2903 return gst_string_wrap_inner (s, len); 2904 } 2905 2906 /* Same as above, but take ownership of the string */ 2907 static gchar * 2908 gst_string_take_and_wrap (gchar * s) 2909 { 2910 gchar *out; 2911 gint len = gst_string_measure_wrapping (s); 2912 2913 if (G_LIKELY (len < 0)) 2914 return s; 2915 2916 out = gst_string_wrap_inner (s, len); 2917 g_free (s); 2918 2919 return out; 2920 } 2921 2922 /* 2923 * This function takes a string delimited with double quotes (") 2924 * and unescapes any \xxx octal numbers. 2925 * 2926 * If sequences of \y are found where y is not in the range of 2927 * 0->3, y is copied unescaped. 2928 * 2929 * If \xyy is found where x is an octal number but y is not, an 2930 * error is encountered and %NULL is returned. 2931 * 2932 * the input string must be \0 terminated. 2933 */ 2934 static gchar * 2935 gst_string_unwrap (const gchar * s) 2936 { 2937 gchar *ret; 2938 gchar *read, *write; 2939 2940 /* NULL string returns NULL */ 2941 if (s == NULL) 2942 return NULL; 2943 2944 /* strings not starting with " are invalid */ 2945 if (*s != '"') 2946 return NULL; 2947 2948 /* make copy of original string to hold the result. This 2949 * string will always be smaller than the original */ 2950 ret = g_strdup (s); 2951 read = ret; 2952 write = ret; 2953 2954 /* need to move to the next position as we parsed the " */ 2955 read++; 2956 2957 while (*read) { 2958 if (GST_ASCII_IS_STRING (*read)) { 2959 /* normal chars are just copied */ 2960 *write++ = *read++; 2961 } else if (*read == '"') { 2962 /* quote marks end of string */ 2963 break; 2964 } else if (*read == '\\') { 2965 /* got an escape char, move to next position to read a tripplet 2966 * of octal numbers */ 2967 read++; 2968 /* is the next char a possible first octal number? */ 2969 if (*read >= '0' && *read <= '3') { 2970 /* parse other 2 numbers, if one of them is not in the range of 2971 * an octal number, we error. We also catch the case where a zero 2972 * byte is found here. */ 2973 if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7') 2974 goto beach; 2975 2976 /* now convert the octal number to a byte again. */ 2977 *write++ = ((read[0] - '0') << 6) + 2978 ((read[1] - '0') << 3) + (read[2] - '0'); 2979 2980 read += 3; 2981 } else { 2982 /* if we run into a \0 here, we definitely won't get a quote later */ 2983 if (*read == 0) 2984 goto beach; 2985 2986 /* else copy \X sequence */ 2987 *write++ = *read++; 2988 } 2989 } else { 2990 /* weird character, error */ 2991 goto beach; 2992 } 2993 } 2994 /* if the string is not ending in " and zero terminated, we error */ 2995 if (*read != '"' || read[1] != '\0') 2996 goto beach; 2997 2998 /* null terminate result string and return */ 2999 *write = '\0'; 3000 return ret; 3001 3002 beach: 3003 g_free (ret); 3004 return NULL; 3005 } 3006 3007 static gchar * 3008 gst_value_serialize_string (const GValue * value) 3009 { 3010 return gst_string_wrap (value->data[0].v_pointer); 3011 } 3012 3013 static gboolean 3014 gst_value_deserialize_string (GValue * dest, const gchar * s) 3015 { 3016 if (G_UNLIKELY (strcmp (s, "NULL") == 0)) { 3017 g_value_set_string (dest, NULL); 3018 return TRUE; 3019 } else if (G_LIKELY (*s != '"')) { 3020 if (!g_utf8_validate (s, -1, NULL)) 3021 return FALSE; 3022 g_value_set_string (dest, s); 3023 return TRUE; 3024 } else { 3025 gchar *str = gst_string_unwrap (s); 3026 if (G_UNLIKELY (!str)) 3027 return FALSE; 3028 g_value_take_string (dest, str); 3029 } 3030 3031 return TRUE; 3032 } 3033 3034 /******** 3035 * enum * 3036 ********/ 3037 3038 static gint 3039 gst_value_compare_enum (const GValue * value1, const GValue * value2) 3040 { 3041 GEnumValue *en1, *en2; 3042 GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1)); 3043 GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2)); 3044 3045 g_return_val_if_fail (klass1, GST_VALUE_UNORDERED); 3046 g_return_val_if_fail (klass2, GST_VALUE_UNORDERED); 3047 en1 = g_enum_get_value (klass1, g_value_get_enum (value1)); 3048 en2 = g_enum_get_value (klass2, g_value_get_enum (value2)); 3049 g_type_class_unref (klass1); 3050 g_type_class_unref (klass2); 3051 g_return_val_if_fail (en1, GST_VALUE_UNORDERED); 3052 g_return_val_if_fail (en2, GST_VALUE_UNORDERED); 3053 if (en1->value < en2->value) 3054 return GST_VALUE_LESS_THAN; 3055 if (en1->value > en2->value) 3056 return GST_VALUE_GREATER_THAN; 3057 3058 return GST_VALUE_EQUAL; 3059 } 3060 3061 static gchar * 3062 gst_value_serialize_enum (const GValue * value) 3063 { 3064 GEnumValue *en; 3065 GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value)); 3066 3067 g_return_val_if_fail (klass, NULL); 3068 en = g_enum_get_value (klass, g_value_get_enum (value)); 3069 g_type_class_unref (klass); 3070 3071 /* might be one of the custom formats registered later */ 3072 if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) { 3073 const GstFormatDefinition *format_def; 3074 3075 format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value)); 3076 g_return_val_if_fail (format_def != NULL, NULL); 3077 return g_strdup (format_def->description); 3078 } 3079 3080 g_return_val_if_fail (en, NULL); 3081 return g_strdup (en->value_name); 3082 } 3083 3084 static gint 3085 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value, 3086 const gchar * s) 3087 { 3088 const GstFormatDefinition *format_def = 3089 g_value_get_pointer (format_def_value); 3090 3091 if (g_ascii_strcasecmp (s, format_def->nick) == 0) 3092 return 0; 3093 3094 return g_ascii_strcasecmp (s, format_def->description); 3095 } 3096 3097 static gboolean 3098 gst_value_deserialize_enum (GValue * dest, const gchar * s) 3099 { 3100 GEnumValue *en; 3101 gchar *endptr = NULL; 3102 GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest)); 3103 3104 g_return_val_if_fail (klass, FALSE); 3105 if (!(en = g_enum_get_value_by_name (klass, s))) { 3106 if (!(en = g_enum_get_value_by_nick (klass, s))) { 3107 gint i = strtol (s, &endptr, 0); 3108 3109 if (endptr && *endptr == '\0') { 3110 en = g_enum_get_value (klass, i); 3111 } 3112 } 3113 } 3114 g_type_class_unref (klass); 3115 3116 /* might be one of the custom formats registered later */ 3117 if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) { 3118 GValue res = { 0, }; 3119 const GstFormatDefinition *format_def; 3120 GstIterator *iter; 3121 gboolean found; 3122 3123 iter = gst_format_iterate_definitions (); 3124 3125 found = gst_iterator_find_custom (iter, 3126 (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s); 3127 3128 if (found) { 3129 format_def = g_value_get_pointer (&res); 3130 g_return_val_if_fail (format_def != NULL, FALSE); 3131 g_value_set_enum (dest, (gint) format_def->value); 3132 g_value_unset (&res); 3133 } 3134 gst_iterator_free (iter); 3135 return found; 3136 } 3137 3138 /* enum name/nick not found */ 3139 if (en == NULL) 3140 return FALSE; 3141 3142 g_value_set_enum (dest, en->value); 3143 return TRUE; 3144 } 3145 3146 /******** 3147 * flags * 3148 ********/ 3149 3150 /* we just compare the value here */ 3151 static gint 3152 gst_value_compare_flags (const GValue * value1, const GValue * value2) 3153 { 3154 guint fl1, fl2; 3155 GFlagsClass *klass1 = 3156 (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1)); 3157 GFlagsClass *klass2 = 3158 (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2)); 3159 3160 g_return_val_if_fail (klass1, GST_VALUE_UNORDERED); 3161 g_return_val_if_fail (klass2, GST_VALUE_UNORDERED); 3162 fl1 = g_value_get_flags (value1); 3163 fl2 = g_value_get_flags (value2); 3164 g_type_class_unref (klass1); 3165 g_type_class_unref (klass2); 3166 if (fl1 < fl2) 3167 return GST_VALUE_LESS_THAN; 3168 if (fl1 > fl2) 3169 return GST_VALUE_GREATER_THAN; 3170 3171 return GST_VALUE_EQUAL; 3172 } 3173 3174 /* the different flags are serialized separated with a + */ 3175 static gchar * 3176 gst_value_serialize_flags (const GValue * value) 3177 { 3178 guint flags; 3179 GFlagsValue *fl; 3180 GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value)); 3181 gchar *result, *tmp; 3182 gboolean first = TRUE; 3183 3184 g_return_val_if_fail (klass, NULL); 3185 3186 flags = g_value_get_flags (value); 3187 3188 /* if no flags are set, try to serialize to the _NONE string */ 3189 if (!flags) { 3190 fl = g_flags_get_first_value (klass, flags); 3191 if (fl) 3192 return g_strdup (fl->value_name); 3193 else 3194 return g_strdup ("0"); 3195 } 3196 3197 /* some flags are set, so serialize one by one */ 3198 result = g_strdup (""); 3199 while (flags) { 3200 fl = g_flags_get_first_value (klass, flags); 3201 if (fl != NULL) { 3202 tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL); 3203 g_free (result); 3204 result = tmp; 3205 first = FALSE; 3206 3207 /* clear flag */ 3208 flags &= ~fl->value; 3209 } 3210 } 3211 g_type_class_unref (klass); 3212 3213 return result; 3214 } 3215 3216 static gboolean 3217 gst_value_deserialize_flags (GValue * dest, const gchar * s) 3218 { 3219 GFlagsValue *fl; 3220 gchar *endptr = NULL; 3221 GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest)); 3222 gchar **split; 3223 guint flags; 3224 gint i; 3225 3226 g_return_val_if_fail (klass, FALSE); 3227 3228 /* split into parts delimited with + */ 3229 split = g_strsplit (s, "+", 0); 3230 3231 flags = 0; 3232 i = 0; 3233 /* loop over each part */ 3234 while (split[i]) { 3235 if (!(fl = g_flags_get_value_by_name (klass, split[i]))) { 3236 if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) { 3237 gint val = strtol (split[i], &endptr, 0); 3238 3239 /* just or numeric value */ 3240 if (endptr && *endptr == '\0') { 3241 flags |= val; 3242 } 3243 } 3244 } 3245 if (fl) { 3246 flags |= fl->value; 3247 } 3248 i++; 3249 } 3250 g_strfreev (split); 3251 g_type_class_unref (klass); 3252 g_value_set_flags (dest, flags); 3253 3254 return TRUE; 3255 } 3256 3257 /**************** 3258 * subset * 3259 ****************/ 3260 3261 static gboolean 3262 gst_value_is_subset_int_range_int_range (const GValue * value1, 3263 const GValue * value2) 3264 { 3265 gint gcd; 3266 3267 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE); 3268 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE); 3269 3270 if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) < 3271 INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) 3272 return FALSE; 3273 if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) > 3274 INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2)) 3275 return FALSE; 3276 3277 if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) { 3278 if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) % 3279 INT_RANGE_STEP (value1)) 3280 return FALSE; 3281 return TRUE; 3282 } 3283 3284 gcd = 3285 gst_util_greatest_common_divisor (INT_RANGE_STEP (value1), 3286 INT_RANGE_STEP (value2)); 3287 if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2))) 3288 return FALSE; 3289 3290 return TRUE; 3291 } 3292 3293 static gboolean 3294 gst_value_is_subset_int64_range_int64_range (const GValue * value1, 3295 const GValue * value2) 3296 { 3297 gint64 gcd; 3298 3299 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE); 3300 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE); 3301 3302 if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2)) 3303 return FALSE; 3304 if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2)) 3305 return FALSE; 3306 3307 if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) { 3308 if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) % 3309 INT64_RANGE_STEP (value1)) 3310 return FALSE; 3311 return TRUE; 3312 } 3313 3314 gcd = 3315 gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1), 3316 INT64_RANGE_STEP (value2)); 3317 if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2))) 3318 return FALSE; 3319 3320 return TRUE; 3321 } 3322 3323 /** 3324 * gst_value_is_subset: 3325 * @value1: a #GValue 3326 * @value2: a #GValue 3327 * 3328 * Check that @value1 is a subset of @value2. 3329 * 3330 * Return: %TRUE is @value1 is a subset of @value2 3331 */ 3332 gboolean 3333 gst_value_is_subset (const GValue * value1, const GValue * value2) 3334 { 3335 /* special case for int/int64 ranges, since we cannot compute 3336 the difference for those when they have different steps, 3337 and it's actually a lot simpler to compute whether a range 3338 is a subset of another. */ 3339 if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) { 3340 return gst_value_is_subset_int_range_int_range (value1, value2); 3341 } else if (GST_VALUE_HOLDS_INT64_RANGE (value1) 3342 && GST_VALUE_HOLDS_INT64_RANGE (value2)) { 3343 return gst_value_is_subset_int64_range_int64_range (value1, value2); 3344 } 3345 3346 /* 3347 * 1 - [1,2] = empty 3348 * -> !subset 3349 * 3350 * [1,2] - 1 = 2 3351 * -> 1 - [1,2] = empty 3352 * -> subset 3353 * 3354 * [1,3] - [1,2] = 3 3355 * -> [1,2] - [1,3] = empty 3356 * -> subset 3357 * 3358 * {1,2} - {1,3} = 2 3359 * -> {1,3} - {1,2} = 3 3360 * -> !subset 3361 * 3362 * First caps subtraction needs to return a non-empty set, second 3363 * subtractions needs to give en empty set. 3364 * Both substractions are switched below, as it's faster that way. 3365 */ 3366 if (!gst_value_subtract (NULL, value1, value2)) { 3367 if (gst_value_subtract (NULL, value2, value1)) { 3368 return TRUE; 3369 } 3370 } 3371 return FALSE; 3372 } 3373 3374 /********* 3375 * union * 3376 *********/ 3377 3378 static gboolean 3379 gst_value_union_int_int_range (GValue * dest, const GValue * src1, 3380 const GValue * src2) 3381 { 3382 gint v = src1->data[0].v_int; 3383 3384 /* check if it's already in the range */ 3385 if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v && 3386 INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v && 3387 v % INT_RANGE_STEP (src2) == 0) { 3388 if (dest) 3389 gst_value_init_and_copy (dest, src2); 3390 return TRUE; 3391 } 3392 3393 /* check if it extends the range */ 3394 if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) { 3395 if (dest) { 3396 guint64 new_min = 3397 (guint) ((INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)); 3398 guint64 new_max = (guint) (INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2)); 3399 3400 gst_value_init_and_copy (dest, src2); 3401 dest->data[0].v_uint64 = (new_min << 32) | (new_max); 3402 } 3403 return TRUE; 3404 } 3405 if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) { 3406 if (dest) { 3407 guint64 new_min = (guint) (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2)); 3408 guint64 new_max = 3409 (guint) ((INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)); 3410 3411 gst_value_init_and_copy (dest, src2); 3412 dest->data[0].v_uint64 = (new_min << 32) | (new_max); 3413 } 3414 return TRUE; 3415 } 3416 3417 return FALSE; 3418 } 3419 3420 static gboolean 3421 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1, 3422 const GValue * src2) 3423 { 3424 /* We can union in several special cases: 3425 1 - one is a subset of another 3426 2 - same step and not disjoint 3427 3 - different step, at least one with one value which matches a 'next' or 'previous' 3428 - anything else ? 3429 */ 3430 3431 /* 1 - subset */ 3432 if (gst_value_is_subset_int_range_int_range (src1, src2)) { 3433 if (dest) 3434 gst_value_init_and_copy (dest, src2); 3435 return TRUE; 3436 } 3437 if (gst_value_is_subset_int_range_int_range (src2, src1)) { 3438 if (dest) 3439 gst_value_init_and_copy (dest, src1); 3440 return TRUE; 3441 } 3442 3443 /* 2 - same step and not disjoint */ 3444 if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) { 3445 if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 && 3446 INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) || 3447 (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 && 3448 INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) { 3449 if (dest) { 3450 gint step = INT_RANGE_STEP (src1); 3451 gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2)); 3452 gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2)); 3453 g_value_init (dest, GST_TYPE_INT_RANGE); 3454 gst_value_set_int_range_step (dest, min, max, step); 3455 } 3456 return TRUE; 3457 } 3458 } 3459 3460 /* 3 - single value matches next or previous */ 3461 if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) { 3462 gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1; 3463 gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1; 3464 if (n1 == 1 || n2 == 1) { 3465 const GValue *range_value = NULL; 3466 gint scalar = 0; 3467 if (n1 == 1) { 3468 range_value = src2; 3469 scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1); 3470 } else if (n2 == 1) { 3471 range_value = src1; 3472 scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2); 3473 } 3474 3475 if (scalar == 3476 (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) { 3477 if (dest) { 3478 guint64 new_min = (guint) 3479 ((INT_RANGE_MIN (range_value) - 3480 1) * INT_RANGE_STEP (range_value)); 3481 guint64 new_max = (guint) 3482 (INT_RANGE_MAX (range_value) * INT_RANGE_STEP (range_value)); 3483 3484 gst_value_init_and_copy (dest, range_value); 3485 dest->data[0].v_uint64 = (new_min << 32) | (new_max); 3486 } 3487 return TRUE; 3488 } else if (scalar == 3489 (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) { 3490 if (dest) { 3491 guint64 new_min = (guint) 3492 (INT_RANGE_MIN (range_value) * INT_RANGE_STEP (range_value)); 3493 guint64 new_max = (guint) 3494 ((INT_RANGE_MAX (range_value) + 3495 1) * INT_RANGE_STEP (range_value)); 3496 gst_value_init_and_copy (dest, range_value); 3497 dest->data[0].v_uint64 = (new_min << 32) | (new_max); 3498 } 3499 return TRUE; 3500 } 3501 } 3502 } 3503 3504 /* If we get there, we did not find a way to make a union that can be 3505 represented with our simplistic model. */ 3506 return FALSE; 3507 } 3508 3509 /**************** 3510 * intersection * 3511 ****************/ 3512 3513 static gboolean 3514 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1, 3515 const GValue * src2) 3516 { 3517 if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int && 3518 INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int && 3519 src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) { 3520 if (dest) 3521 gst_value_init_and_copy (dest, src1); 3522 return TRUE; 3523 } 3524 3525 return FALSE; 3526 } 3527 3528 static gboolean 3529 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1, 3530 const GValue * src2) 3531 { 3532 gint min; 3533 gint max; 3534 gint step; 3535 3536 step = 3537 INT_RANGE_STEP (src1) / 3538 gst_util_greatest_common_divisor (INT_RANGE_STEP (src1), 3539 INT_RANGE_STEP (src2)); 3540 if (G_MAXINT32 / INT_RANGE_STEP (src2) < step) 3541 return FALSE; 3542 step *= INT_RANGE_STEP (src2); 3543 3544 min = 3545 MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1), 3546 INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2)); 3547 min = (min + step - 1) / step * step; 3548 max = 3549 MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1), 3550 INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2)); 3551 max = max / step * step; 3552 3553 if (min < max) { 3554 if (dest) { 3555 g_value_init (dest, GST_TYPE_INT_RANGE); 3556 gst_value_set_int_range_step (dest, min, max, step); 3557 } 3558 return TRUE; 3559 } 3560 if (min == max) { 3561 if (dest) { 3562 g_value_init (dest, G_TYPE_INT); 3563 g_value_set_int (dest, min); 3564 } 3565 return TRUE; 3566 } 3567 3568 return FALSE; 3569 } 3570 3571 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v)) 3572 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v)) 3573 3574 static gboolean 3575 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1, 3576 const GValue * src2) 3577 { 3578 if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 && 3579 INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 && 3580 src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) { 3581 if (dest) 3582 gst_value_init_and_copy (dest, src1); 3583 return TRUE; 3584 } 3585 3586 return FALSE; 3587 } 3588 3589 static gboolean 3590 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1, 3591 const GValue * src2) 3592 { 3593 gint64 min; 3594 gint64 max; 3595 gint64 step; 3596 3597 step = 3598 INT64_RANGE_STEP (src1) / 3599 gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1), 3600 INT64_RANGE_STEP (src2)); 3601 if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step) 3602 return FALSE; 3603 step *= INT64_RANGE_STEP (src2); 3604 3605 min = 3606 MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1), 3607 INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2)); 3608 min = (min + step - 1) / step * step; 3609 max = 3610 MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1), 3611 INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2)); 3612 max = max / step * step; 3613 3614 if (min < max) { 3615 if (dest) { 3616 g_value_init (dest, GST_TYPE_INT64_RANGE); 3617 gst_value_set_int64_range_step (dest, min, max, step); 3618 } 3619 return TRUE; 3620 } 3621 if (min == max) { 3622 if (dest) { 3623 g_value_init (dest, G_TYPE_INT64); 3624 g_value_set_int64 (dest, min); 3625 } 3626 return TRUE; 3627 } 3628 3629 return FALSE; 3630 } 3631 3632 static gboolean 3633 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1, 3634 const GValue * src2) 3635 { 3636 if (src2->data[0].v_double <= src1->data[0].v_double && 3637 src2->data[1].v_double >= src1->data[0].v_double) { 3638 if (dest) 3639 gst_value_init_and_copy (dest, src1); 3640 return TRUE; 3641 } 3642 3643 return FALSE; 3644 } 3645 3646 static gboolean 3647 gst_value_intersect_double_range_double_range (GValue * dest, 3648 const GValue * src1, const GValue * src2) 3649 { 3650 gdouble min; 3651 gdouble max; 3652 3653 min = MAX (src1->data[0].v_double, src2->data[0].v_double); 3654 max = MIN (src1->data[1].v_double, src2->data[1].v_double); 3655 3656 if (min < max) { 3657 if (dest) { 3658 g_value_init (dest, GST_TYPE_DOUBLE_RANGE); 3659 gst_value_set_double_range (dest, min, max); 3660 } 3661 return TRUE; 3662 } 3663 if (min == max) { 3664 if (dest) { 3665 g_value_init (dest, G_TYPE_DOUBLE); 3666 g_value_set_int (dest, (int) min); 3667 } 3668 return TRUE; 3669 } 3670 3671 return FALSE; 3672 } 3673 3674 static gboolean 3675 gst_value_intersect_list (GValue * dest, const GValue * value1, 3676 const GValue * value2) 3677 { 3678 guint i, size; 3679 GValue intersection = { 0, }; 3680 gboolean ret = FALSE; 3681 3682 size = VALUE_LIST_SIZE (value1); 3683 for (i = 0; i < size; i++) { 3684 const GValue *cur = VALUE_LIST_GET_VALUE (value1, i); 3685 3686 /* quicker version when we don't need the resulting set */ 3687 if (!dest) { 3688 if (gst_value_intersect (NULL, cur, value2)) { 3689 ret = TRUE; 3690 break; 3691 } 3692 continue; 3693 } 3694 3695 if (gst_value_intersect (&intersection, cur, value2)) { 3696 /* append value */ 3697 if (!ret) { 3698 gst_value_move (dest, &intersection); 3699 ret = TRUE; 3700 } else if (GST_VALUE_HOLDS_LIST (dest)) { 3701 _gst_value_list_append_and_take_value (dest, &intersection); 3702 } else { 3703 GValue temp; 3704 3705 gst_value_move (&temp, dest); 3706 gst_value_list_merge (dest, &temp, &intersection); 3707 g_value_unset (&temp); 3708 g_value_unset (&intersection); 3709 } 3710 } 3711 } 3712 3713 return ret; 3714 } 3715 3716 static gboolean 3717 gst_value_intersect_array (GValue * dest, const GValue * src1, 3718 const GValue * src2) 3719 { 3720 guint size; 3721 guint n; 3722 GValue val = { 0 }; 3723 3724 /* only works on similar-sized arrays */ 3725 size = gst_value_array_get_size (src1); 3726 if (size != gst_value_array_get_size (src2)) 3727 return FALSE; 3728 3729 /* quicker value when we don't need the resulting set */ 3730 if (!dest) { 3731 for (n = 0; n < size; n++) { 3732 if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n), 3733 gst_value_array_get_value (src2, n))) { 3734 return FALSE; 3735 } 3736 } 3737 return TRUE; 3738 } 3739 3740 g_value_init (dest, GST_TYPE_ARRAY); 3741 3742 for (n = 0; n < size; n++) { 3743 if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n), 3744 gst_value_array_get_value (src2, n))) { 3745 g_value_unset (dest); 3746 return FALSE; 3747 } 3748 _gst_value_array_append_and_take_value (dest, &val); 3749 } 3750 3751 return TRUE; 3752 } 3753 3754 static gboolean 3755 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1, 3756 const GValue * src2) 3757 { 3758 gint res1, res2; 3759 GValue *vals; 3760 GstValueCompareFunc compare; 3761 3762 vals = src2->data[0].v_pointer; 3763 3764 if (vals == NULL) 3765 return FALSE; 3766 3767 if ((compare = gst_value_get_compare_func (src1))) { 3768 res1 = gst_value_compare_with_func (&vals[0], src1, compare); 3769 res2 = gst_value_compare_with_func (&vals[1], src1, compare); 3770 3771 if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) && 3772 (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) { 3773 if (dest) 3774 gst_value_init_and_copy (dest, src1); 3775 return TRUE; 3776 } 3777 } 3778 3779 return FALSE; 3780 } 3781 3782 static gboolean 3783 gst_value_intersect_fraction_range_fraction_range (GValue * dest, 3784 const GValue * src1, const GValue * src2) 3785 { 3786 GValue *min; 3787 GValue *max; 3788 gint res; 3789 GValue *vals1, *vals2; 3790 GstValueCompareFunc compare; 3791 3792 vals1 = src1->data[0].v_pointer; 3793 vals2 = src2->data[0].v_pointer; 3794 g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE); 3795 3796 if ((compare = gst_value_get_compare_func (&vals1[0]))) { 3797 /* min = MAX (src1.start, src2.start) */ 3798 res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare); 3799 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); 3800 if (res == GST_VALUE_LESS_THAN) 3801 min = &vals2[0]; /* Take the max of the 2 */ 3802 else 3803 min = &vals1[0]; 3804 3805 /* max = MIN (src1.end, src2.end) */ 3806 res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare); 3807 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); 3808 if (res == GST_VALUE_GREATER_THAN) 3809 max = &vals2[1]; /* Take the min of the 2 */ 3810 else 3811 max = &vals1[1]; 3812 3813 res = gst_value_compare_with_func (min, max, compare); 3814 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); 3815 if (res == GST_VALUE_LESS_THAN) { 3816 if (dest) { 3817 g_value_init (dest, GST_TYPE_FRACTION_RANGE); 3818 vals1 = dest->data[0].v_pointer; 3819 g_value_copy (min, &vals1[0]); 3820 g_value_copy (max, &vals1[1]); 3821 } 3822 return TRUE; 3823 } 3824 if (res == GST_VALUE_EQUAL) { 3825 if (dest) 3826 gst_value_init_and_copy (dest, min); 3827 return TRUE; 3828 } 3829 } 3830 3831 return FALSE; 3832 } 3833 3834 /*************** 3835 * subtraction * 3836 ***************/ 3837 3838 static gboolean 3839 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend, 3840 const GValue * subtrahend) 3841 { 3842 gint min = gst_value_get_int_range_min (subtrahend); 3843 gint max = gst_value_get_int_range_max (subtrahend); 3844 gint step = gst_value_get_int_range_step (subtrahend); 3845 gint val = g_value_get_int (minuend); 3846 3847 if (step == 0) 3848 return FALSE; 3849 3850 /* subtracting a range from an int only works if the int is not in the 3851 * range */ 3852 if (val < min || val > max || val % step) { 3853 /* and the result is the int */ 3854 if (dest) 3855 gst_value_init_and_copy (dest, minuend); 3856 return TRUE; 3857 } 3858 return FALSE; 3859 } 3860 3861 /* creates a new int range based on input values. 3862 */ 3863 static gboolean 3864 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2, 3865 gint max2, gint step) 3866 { 3867 GValue v1 = { 0, }; 3868 GValue v2 = { 0, }; 3869 GValue *pv1, *pv2; /* yeah, hungarian! */ 3870 3871 g_return_val_if_fail (step > 0, FALSE); 3872 g_return_val_if_fail (min1 % step == 0, FALSE); 3873 g_return_val_if_fail (max1 % step == 0, FALSE); 3874 g_return_val_if_fail (min2 % step == 0, FALSE); 3875 g_return_val_if_fail (max2 % step == 0, FALSE); 3876 3877 if (min1 <= max1 && min2 <= max2) { 3878 pv1 = &v1; 3879 pv2 = &v2; 3880 } else if (min1 <= max1) { 3881 pv1 = dest; 3882 pv2 = NULL; 3883 } else if (min2 <= max2) { 3884 pv1 = NULL; 3885 pv2 = dest; 3886 } else { 3887 return FALSE; 3888 } 3889 3890 if (!dest) 3891 return TRUE; 3892 3893 if (min1 < max1) { 3894 g_value_init (pv1, GST_TYPE_INT_RANGE); 3895 gst_value_set_int_range_step (pv1, min1, max1, step); 3896 } else if (min1 == max1) { 3897 g_value_init (pv1, G_TYPE_INT); 3898 g_value_set_int (pv1, min1); 3899 } 3900 if (min2 < max2) { 3901 g_value_init (pv2, GST_TYPE_INT_RANGE); 3902 gst_value_set_int_range_step (pv2, min2, max2, step); 3903 } else if (min2 == max2) { 3904 g_value_init (pv2, G_TYPE_INT); 3905 g_value_set_int (pv2, min2); 3906 } 3907 3908 if (min1 <= max1 && min2 <= max2) { 3909 gst_value_list_concat_and_take_values (dest, pv1, pv2); 3910 } 3911 return TRUE; 3912 } 3913 3914 static gboolean 3915 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend, 3916 const GValue * subtrahend) 3917 { 3918 gint min = gst_value_get_int_range_min (minuend); 3919 gint max = gst_value_get_int_range_max (minuend); 3920 gint step = gst_value_get_int_range_step (minuend); 3921 gint val = g_value_get_int (subtrahend); 3922 3923 g_return_val_if_fail (min < max, FALSE); 3924 3925 if (step == 0) 3926 return FALSE; 3927 3928 /* value is outside of the range, return range unchanged */ 3929 if (val < min || val > max || val % step) { 3930 if (dest) 3931 gst_value_init_and_copy (dest, minuend); 3932 return TRUE; 3933 } else { 3934 /* max must be MAXINT too as val <= max */ 3935 if (val >= G_MAXINT - step + 1) { 3936 max -= step; 3937 val -= step; 3938 } 3939 /* min must be MININT too as val >= max */ 3940 if (val <= G_MININT + step - 1) { 3941 min += step; 3942 val += step; 3943 } 3944 if (dest) 3945 gst_value_create_new_range (dest, min, val - step, val + step, max, step); 3946 } 3947 return TRUE; 3948 } 3949 3950 static gboolean 3951 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend, 3952 const GValue * subtrahend) 3953 { 3954 gint min1 = gst_value_get_int_range_min (minuend); 3955 gint max1 = gst_value_get_int_range_max (minuend); 3956 gint step1 = gst_value_get_int_range_step (minuend); 3957 gint min2 = gst_value_get_int_range_min (subtrahend); 3958 gint max2 = gst_value_get_int_range_max (subtrahend); 3959 gint step2 = gst_value_get_int_range_step (subtrahend); 3960 gint step; 3961 3962 if (step1 != step2) { 3963 /* ENOIMPL */ 3964 g_assert (FALSE); 3965 return FALSE; 3966 } 3967 step = step1; 3968 3969 if (step == 0) 3970 return FALSE; 3971 3972 if (max2 >= max1 && min2 <= min1) { 3973 return FALSE; 3974 } else if (max2 >= max1) { 3975 return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1), 3976 step, 0, step); 3977 } else if (min2 <= min1) { 3978 return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1, 3979 step, 0, step); 3980 } else { 3981 return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1), 3982 MAX (max2 + step, min1), max1, step); 3983 } 3984 } 3985 3986 static gboolean 3987 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend, 3988 const GValue * subtrahend) 3989 { 3990 gint64 min = gst_value_get_int64_range_min (subtrahend); 3991 gint64 max = gst_value_get_int64_range_max (subtrahend); 3992 gint64 step = gst_value_get_int64_range_step (subtrahend); 3993 gint64 val = g_value_get_int64 (minuend); 3994 3995 if (step == 0) 3996 return FALSE; 3997 /* subtracting a range from an int64 only works if the int64 is not in the 3998 * range */ 3999 if (val < min || val > max || val % step) { 4000 /* and the result is the int64 */ 4001 if (dest) 4002 gst_value_init_and_copy (dest, minuend); 4003 return TRUE; 4004 } 4005 return FALSE; 4006 } 4007 4008 /* creates a new int64 range based on input values. 4009 */ 4010 static gboolean 4011 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1, 4012 gint64 min2, gint64 max2, gint64 step) 4013 { 4014 GValue v1 = { 0, }; 4015 GValue v2 = { 0, }; 4016 GValue *pv1, *pv2; /* yeah, hungarian! */ 4017 4018 g_return_val_if_fail (step > 0, FALSE); 4019 g_return_val_if_fail (min1 % step == 0, FALSE); 4020 g_return_val_if_fail (max1 % step == 0, FALSE); 4021 g_return_val_if_fail (min2 % step == 0, FALSE); 4022 g_return_val_if_fail (max2 % step == 0, FALSE); 4023 4024 if (min1 <= max1 && min2 <= max2) { 4025 pv1 = &v1; 4026 pv2 = &v2; 4027 } else if (min1 <= max1) { 4028 pv1 = dest; 4029 pv2 = NULL; 4030 } else if (min2 <= max2) { 4031 pv1 = NULL; 4032 pv2 = dest; 4033 } else { 4034 return FALSE; 4035 } 4036 4037 if (!dest) 4038 return TRUE; 4039 4040 if (min1 < max1) { 4041 g_value_init (pv1, GST_TYPE_INT64_RANGE); 4042 gst_value_set_int64_range_step (pv1, min1, max1, step); 4043 } else if (min1 == max1) { 4044 g_value_init (pv1, G_TYPE_INT64); 4045 g_value_set_int64 (pv1, min1); 4046 } 4047 if (min2 < max2) { 4048 g_value_init (pv2, GST_TYPE_INT64_RANGE); 4049 gst_value_set_int64_range_step (pv2, min2, max2, step); 4050 } else if (min2 == max2) { 4051 g_value_init (pv2, G_TYPE_INT64); 4052 g_value_set_int64 (pv2, min2); 4053 } 4054 4055 if (min1 <= max1 && min2 <= max2) { 4056 gst_value_list_concat_and_take_values (dest, pv1, pv2); 4057 } 4058 return TRUE; 4059 } 4060 4061 static gboolean 4062 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend, 4063 const GValue * subtrahend) 4064 { 4065 gint64 min = gst_value_get_int64_range_min (minuend); 4066 gint64 max = gst_value_get_int64_range_max (minuend); 4067 gint64 step = gst_value_get_int64_range_step (minuend); 4068 gint64 val = g_value_get_int64 (subtrahend); 4069 4070 g_return_val_if_fail (min < max, FALSE); 4071 4072 if (step == 0) 4073 return FALSE; 4074 4075 /* value is outside of the range, return range unchanged */ 4076 if (val < min || val > max || val % step) { 4077 if (dest) 4078 gst_value_init_and_copy (dest, minuend); 4079 return TRUE; 4080 } else { 4081 /* max must be MAXINT64 too as val <= max */ 4082 if (val >= G_MAXINT64 - step + 1) { 4083 max -= step; 4084 val -= step; 4085 } 4086 /* min must be MININT64 too as val >= max */ 4087 if (val <= G_MININT64 + step - 1) { 4088 min += step; 4089 val += step; 4090 } 4091 if (dest) 4092 gst_value_create_new_int64_range (dest, min, val - step, val + step, max, 4093 step); 4094 } 4095 return TRUE; 4096 } 4097 4098 static gboolean 4099 gst_value_subtract_int64_range_int64_range (GValue * dest, 4100 const GValue * minuend, const GValue * subtrahend) 4101 { 4102 gint64 min1 = gst_value_get_int64_range_min (minuend); 4103 gint64 max1 = gst_value_get_int64_range_max (minuend); 4104 gint64 step1 = gst_value_get_int64_range_step (minuend); 4105 gint64 min2 = gst_value_get_int64_range_min (subtrahend); 4106 gint64 max2 = gst_value_get_int64_range_max (subtrahend); 4107 gint64 step2 = gst_value_get_int64_range_step (subtrahend); 4108 gint64 step; 4109 4110 if (step1 != step2) { 4111 /* ENOIMPL */ 4112 g_assert (FALSE); 4113 return FALSE; 4114 } 4115 4116 if (step1 == 0) 4117 return FALSE; 4118 4119 step = step1; 4120 4121 if (max2 >= max1 && min2 <= min1) { 4122 return FALSE; 4123 } else if (max2 >= max1) { 4124 return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step, 4125 max1), step, 0, step); 4126 } else if (min2 <= min1) { 4127 return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1), 4128 max1, step, 0, step); 4129 } else { 4130 return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step, 4131 max1), MAX (max2 + step, min1), max1, step); 4132 } 4133 } 4134 4135 static gboolean 4136 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend, 4137 const GValue * subtrahend) 4138 { 4139 gdouble min = gst_value_get_double_range_min (subtrahend); 4140 gdouble max = gst_value_get_double_range_max (subtrahend); 4141 gdouble val = g_value_get_double (minuend); 4142 4143 if (val < min || val > max) { 4144 if (dest) 4145 gst_value_init_and_copy (dest, minuend); 4146 return TRUE; 4147 } 4148 return FALSE; 4149 } 4150 4151 static gboolean 4152 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend, 4153 const GValue * subtrahend) 4154 { 4155 /* since we don't have open ranges, we cannot create a hole in 4156 * a double range. We return the original range */ 4157 if (dest) 4158 gst_value_init_and_copy (dest, minuend); 4159 return TRUE; 4160 } 4161 4162 static gboolean 4163 gst_value_subtract_double_range_double_range (GValue * dest, 4164 const GValue * minuend, const GValue * subtrahend) 4165 { 4166 /* since we don't have open ranges, we have to approximate */ 4167 /* done like with ints */ 4168 gdouble min1 = gst_value_get_double_range_min (minuend); 4169 gdouble max2 = gst_value_get_double_range_max (minuend); 4170 gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2); 4171 gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1); 4172 GValue v1 = { 0, }; 4173 GValue v2 = { 0, }; 4174 GValue *pv1, *pv2; /* yeah, hungarian! */ 4175 4176 if (min1 < max1 && min2 < max2) { 4177 pv1 = &v1; 4178 pv2 = &v2; 4179 } else if (min1 < max1) { 4180 pv1 = dest; 4181 pv2 = NULL; 4182 } else if (min2 < max2) { 4183 pv1 = NULL; 4184 pv2 = dest; 4185 } else { 4186 return FALSE; 4187 } 4188 4189 if (!dest) 4190 return TRUE; 4191 4192 if (min1 < max1) { 4193 g_value_init (pv1, GST_TYPE_DOUBLE_RANGE); 4194 gst_value_set_double_range (pv1, min1, max1); 4195 } 4196 if (min2 < max2) { 4197 g_value_init (pv2, GST_TYPE_DOUBLE_RANGE); 4198 gst_value_set_double_range (pv2, min2, max2); 4199 } 4200 4201 if (min1 < max1 && min2 < max2) { 4202 gst_value_list_concat_and_take_values (dest, pv1, pv2); 4203 } 4204 return TRUE; 4205 } 4206 4207 static gboolean 4208 gst_value_subtract_from_list (GValue * dest, const GValue * minuend, 4209 const GValue * subtrahend) 4210 { 4211 guint i, size; 4212 GValue subtraction = { 0, }; 4213 gboolean ret = FALSE; 4214 4215 size = VALUE_LIST_SIZE (minuend); 4216 for (i = 0; i < size; i++) { 4217 const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i); 4218 4219 /* quicker version when we can discard the result */ 4220 if (!dest) { 4221 if (gst_value_subtract (NULL, cur, subtrahend)) { 4222 ret = TRUE; 4223 break; 4224 } 4225 continue; 4226 } 4227 4228 if (gst_value_subtract (&subtraction, cur, subtrahend)) { 4229 if (!ret) { 4230 gst_value_move (dest, &subtraction); 4231 ret = TRUE; 4232 } else if (G_VALUE_TYPE (dest) == GST_TYPE_LIST 4233 && G_VALUE_TYPE (&subtraction) != GST_TYPE_LIST) { 4234 _gst_value_list_append_and_take_value (dest, &subtraction); 4235 } else { 4236 GValue temp; 4237 4238 gst_value_move (&temp, dest); 4239 gst_value_list_concat_and_take_values (dest, &temp, &subtraction); 4240 } 4241 } 4242 } 4243 return ret; 4244 } 4245 4246 static gboolean 4247 gst_value_subtract_list (GValue * dest, const GValue * minuend, 4248 const GValue * subtrahend) 4249 { 4250 guint i, size; 4251 GValue data[2] = { {0,}, {0,} }; 4252 GValue *subtraction = &data[0], *result = &data[1]; 4253 4254 gst_value_init_and_copy (result, minuend); 4255 size = VALUE_LIST_SIZE (subtrahend); 4256 for (i = 0; i < size; i++) { 4257 const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i); 4258 4259 if (gst_value_subtract (subtraction, result, cur)) { 4260 GValue *temp = result; 4261 4262 result = subtraction; 4263 subtraction = temp; 4264 g_value_unset (subtraction); 4265 } else { 4266 g_value_unset (result); 4267 return FALSE; 4268 } 4269 } 4270 if (dest) { 4271 gst_value_move (dest, result); 4272 } else { 4273 g_value_unset (result); 4274 } 4275 return TRUE; 4276 } 4277 4278 static gboolean 4279 gst_value_subtract_fraction_fraction_range (GValue * dest, 4280 const GValue * minuend, const GValue * subtrahend) 4281 { 4282 const GValue *min = gst_value_get_fraction_range_min (subtrahend); 4283 const GValue *max = gst_value_get_fraction_range_max (subtrahend); 4284 GstValueCompareFunc compare; 4285 4286 if ((compare = gst_value_get_compare_func (minuend))) { 4287 /* subtracting a range from an fraction only works if the fraction 4288 * is not in the range */ 4289 if (gst_value_compare_with_func (minuend, min, compare) == 4290 GST_VALUE_LESS_THAN || 4291 gst_value_compare_with_func (minuend, max, compare) == 4292 GST_VALUE_GREATER_THAN) { 4293 /* and the result is the value */ 4294 if (dest) 4295 gst_value_init_and_copy (dest, minuend); 4296 return TRUE; 4297 } 4298 } 4299 return FALSE; 4300 } 4301 4302 static gboolean 4303 gst_value_subtract_fraction_range_fraction (GValue * dest, 4304 const GValue * minuend, const GValue * subtrahend) 4305 { 4306 /* since we don't have open ranges, we cannot create a hole in 4307 * a range. We return the original range */ 4308 if (dest) 4309 gst_value_init_and_copy (dest, minuend); 4310 return TRUE; 4311 } 4312 4313 static gboolean 4314 gst_value_subtract_fraction_range_fraction_range (GValue * dest, 4315 const GValue * minuend, const GValue * subtrahend) 4316 { 4317 /* since we don't have open ranges, we have to approximate */ 4318 /* done like with ints and doubles. Creates a list of 2 fraction ranges */ 4319 const GValue *min1 = gst_value_get_fraction_range_min (minuend); 4320 const GValue *max2 = gst_value_get_fraction_range_max (minuend); 4321 const GValue *max1 = gst_value_get_fraction_range_min (subtrahend); 4322 const GValue *min2 = gst_value_get_fraction_range_max (subtrahend); 4323 gint cmp1, cmp2; 4324 GValue v1 = { 0, }; 4325 GValue v2 = { 0, }; 4326 GValue *pv1, *pv2; /* yeah, hungarian! */ 4327 GstValueCompareFunc compare; 4328 4329 g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE); 4330 g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE); 4331 4332 compare = gst_value_get_compare_func (min1); 4333 g_return_val_if_fail (compare, FALSE); 4334 4335 cmp1 = gst_value_compare_with_func (max2, max1, compare); 4336 g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE); 4337 if (cmp1 == GST_VALUE_LESS_THAN) 4338 max1 = max2; 4339 cmp1 = gst_value_compare_with_func (min1, min2, compare); 4340 g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE); 4341 if (cmp1 == GST_VALUE_GREATER_THAN) 4342 min2 = min1; 4343 4344 cmp1 = gst_value_compare_with_func (min1, max1, compare); 4345 cmp2 = gst_value_compare_with_func (min2, max2, compare); 4346 4347 if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) { 4348 pv1 = &v1; 4349 pv2 = &v2; 4350 } else if (cmp1 == GST_VALUE_LESS_THAN) { 4351 pv1 = dest; 4352 pv2 = NULL; 4353 } else if (cmp2 == GST_VALUE_LESS_THAN) { 4354 pv1 = NULL; 4355 pv2 = dest; 4356 } else { 4357 return FALSE; 4358 } 4359 4360 if (!dest) 4361 return TRUE; 4362 4363 if (cmp1 == GST_VALUE_LESS_THAN) { 4364 g_value_init (pv1, GST_TYPE_FRACTION_RANGE); 4365 gst_value_set_fraction_range (pv1, min1, max1); 4366 } 4367 if (cmp2 == GST_VALUE_LESS_THAN) { 4368 g_value_init (pv2, GST_TYPE_FRACTION_RANGE); 4369 gst_value_set_fraction_range (pv2, min2, max2); 4370 } 4371 4372 if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) { 4373 gst_value_list_concat_and_take_values (dest, pv1, pv2); 4374 } 4375 return TRUE; 4376 } 4377 4378 4379 /************** 4380 * comparison * 4381 **************/ 4382 4383 /* 4384 * gst_value_get_compare_func: 4385 * @value1: a value to get the compare function for 4386 * 4387 * Determines the compare function to be used with values of the same type as 4388 * @value1. The function can be given to gst_value_compare_with_func(). 4389 * 4390 * Returns: A #GstValueCompareFunc value 4391 */ 4392 static GstValueCompareFunc 4393 gst_value_get_compare_func (const GValue * value1) 4394 { 4395 GstValueTable *table, *best = NULL; 4396 guint i; 4397 GType type1; 4398 4399 type1 = G_VALUE_TYPE (value1); 4400 4401 /* this is a fast check */ 4402 best = gst_value_hash_lookup_type (type1); 4403 4404 /* slower checks */ 4405 if (G_UNLIKELY (!best || !best->compare)) { 4406 guint len = gst_value_table->len; 4407 4408 best = NULL; 4409 for (i = 0; i < len; i++) { 4410 table = &g_array_index (gst_value_table, GstValueTable, i); 4411 if (table->compare && g_type_is_a (type1, table->type)) { 4412 if (!best || g_type_is_a (table->type, best->type)) 4413 best = table; 4414 } 4415 } 4416 } 4417 if (G_LIKELY (best)) 4418 return best->compare; 4419 4420 return NULL; 4421 } 4422 4423 static inline gboolean 4424 gst_value_can_compare_unchecked (const GValue * value1, const GValue * value2) 4425 { 4426 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) 4427 return FALSE; 4428 4429 return gst_value_get_compare_func (value1) != NULL; 4430 } 4431 4432 /** 4433 * gst_value_can_compare: 4434 * @value1: a value to compare 4435 * @value2: another value to compare 4436 * 4437 * Determines if @value1 and @value2 can be compared. 4438 * 4439 * Returns: %TRUE if the values can be compared 4440 */ 4441 gboolean 4442 gst_value_can_compare (const GValue * value1, const GValue * value2) 4443 { 4444 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 4445 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 4446 4447 return gst_value_can_compare_unchecked (value1, value2); 4448 } 4449 4450 static gboolean 4451 gst_value_list_equals_range (const GValue * list, const GValue * value) 4452 { 4453 const GValue *first; 4454 guint list_size, n; 4455 4456 g_assert (G_IS_VALUE (list)); 4457 g_assert (G_IS_VALUE (value)); 4458 g_assert (GST_VALUE_HOLDS_LIST (list)); 4459 4460 /* TODO: compare against an empty list ? No type though... */ 4461 list_size = VALUE_LIST_SIZE (list); 4462 if (list_size == 0) 4463 return FALSE; 4464 4465 /* compare the basic types - they have to match */ 4466 first = VALUE_LIST_GET_VALUE (list, 0); 4467 #define CHECK_TYPES(type,prefix) \ 4468 (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value)) 4469 if (CHECK_TYPES (INT, G)) { 4470 const gint rmin = gst_value_get_int_range_min (value); 4471 const gint rmax = gst_value_get_int_range_max (value); 4472 const gint rstep = gst_value_get_int_range_step (value); 4473 if (rstep == 0) 4474 return FALSE; 4475 /* note: this will overflow for min 0 and max INT_MAX, but this 4476 would only be equal to a list of INT_MAX elements, which seems 4477 very unlikely */ 4478 if (list_size != rmax / rstep - rmin / rstep + 1) 4479 return FALSE; 4480 for (n = 0; n < list_size; ++n) { 4481 gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n)); 4482 if (v < rmin || v > rmax || v % rstep) { 4483 return FALSE; 4484 } 4485 } 4486 return TRUE; 4487 } else if (CHECK_TYPES (INT64, G)) { 4488 const gint64 rmin = gst_value_get_int64_range_min (value); 4489 const gint64 rmax = gst_value_get_int64_range_max (value); 4490 const gint64 rstep = gst_value_get_int64_range_step (value); 4491 GST_DEBUG ("List/range of int64s"); 4492 if (rstep == 0) 4493 return FALSE; 4494 if (list_size != rmax / rstep - rmin / rstep + 1) 4495 return FALSE; 4496 for (n = 0; n < list_size; ++n) { 4497 gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n)); 4498 if (v < rmin || v > rmax || v % rstep) 4499 return FALSE; 4500 } 4501 return TRUE; 4502 } 4503 #undef CHECK_TYPES 4504 4505 /* other combinations don't make sense for equality */ 4506 return FALSE; 4507 } 4508 4509 /* "Pure" variant of gst_value_compare which is guaranteed to 4510 * not have list arguments and therefore does basic comparisions 4511 */ 4512 static inline gint 4513 _gst_value_compare_nolist (const GValue * value1, const GValue * value2) 4514 { 4515 GstValueCompareFunc compare; 4516 4517 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) 4518 return GST_VALUE_UNORDERED; 4519 4520 compare = gst_value_get_compare_func (value1); 4521 if (compare) { 4522 return compare (value1, value2); 4523 } 4524 4525 g_critical ("unable to compare values of type %s\n", 4526 g_type_name (G_VALUE_TYPE (value1))); 4527 return GST_VALUE_UNORDERED; 4528 } 4529 4530 /** 4531 * gst_value_compare: 4532 * @value1: a value to compare 4533 * @value2: another value to compare 4534 * 4535 * Compares @value1 and @value2. If @value1 and @value2 cannot be 4536 * compared, the function returns GST_VALUE_UNORDERED. Otherwise, 4537 * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned. 4538 * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned. 4539 * If the values are equal, GST_VALUE_EQUAL is returned. 4540 * 4541 * Returns: comparison result 4542 */ 4543 gint 4544 gst_value_compare (const GValue * value1, const GValue * value2) 4545 { 4546 gboolean value1_is_list; 4547 gboolean value2_is_list; 4548 4549 g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN); 4550 g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN); 4551 4552 value1_is_list = G_VALUE_TYPE (value1) == GST_TYPE_LIST; 4553 value2_is_list = G_VALUE_TYPE (value2) == GST_TYPE_LIST; 4554 4555 /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal), 4556 as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */ 4557 if (value1_is_list && !value2_is_list) { 4558 gint i, n, ret; 4559 4560 if (gst_value_list_equals_range (value1, value2)) { 4561 return GST_VALUE_EQUAL; 4562 } 4563 4564 n = gst_value_list_get_size (value1); 4565 if (n == 0) 4566 return GST_VALUE_UNORDERED; 4567 4568 for (i = 0; i < n; i++) { 4569 const GValue *elt; 4570 4571 elt = gst_value_list_get_value (value1, i); 4572 ret = gst_value_compare (elt, value2); 4573 if (ret != GST_VALUE_EQUAL && n == 1) 4574 return ret; 4575 else if (ret != GST_VALUE_EQUAL) 4576 return GST_VALUE_UNORDERED; 4577 } 4578 4579 return GST_VALUE_EQUAL; 4580 } else if (value2_is_list && !value1_is_list) { 4581 gint i, n, ret; 4582 4583 if (gst_value_list_equals_range (value2, value1)) { 4584 return GST_VALUE_EQUAL; 4585 } 4586 4587 n = gst_value_list_get_size (value2); 4588 if (n == 0) 4589 return GST_VALUE_UNORDERED; 4590 4591 for (i = 0; i < n; i++) { 4592 const GValue *elt; 4593 4594 elt = gst_value_list_get_value (value2, i); 4595 ret = gst_value_compare (elt, value1); 4596 if (ret != GST_VALUE_EQUAL && n == 1) 4597 return ret; 4598 else if (ret != GST_VALUE_EQUAL) 4599 return GST_VALUE_UNORDERED; 4600 } 4601 4602 return GST_VALUE_EQUAL; 4603 } 4604 4605 /* And now handle the generic case */ 4606 return _gst_value_compare_nolist (value1, value2); 4607 } 4608 4609 /* 4610 * gst_value_compare_with_func: 4611 * @value1: a value to compare 4612 * @value2: another value to compare 4613 * @compare: compare function 4614 * 4615 * Compares @value1 and @value2 using the @compare function. Works like 4616 * gst_value_compare() but allows to save time determining the compare function 4617 * a multiple times. 4618 * 4619 * Returns: comparison result 4620 */ 4621 static gint 4622 gst_value_compare_with_func (const GValue * value1, const GValue * value2, 4623 GstValueCompareFunc compare) 4624 { 4625 g_assert (compare); 4626 4627 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) 4628 return GST_VALUE_UNORDERED; 4629 4630 return compare (value1, value2); 4631 } 4632 4633 /* union */ 4634 4635 /** 4636 * gst_value_can_union: 4637 * @value1: a value to union 4638 * @value2: another value to union 4639 * 4640 * Determines if @value1 and @value2 can be non-trivially unioned. 4641 * Any two values can be trivially unioned by adding both of them 4642 * to a GstValueList. However, certain types have the possibility 4643 * to be unioned in a simpler way. For example, an integer range 4644 * and an integer can be unioned if the integer is a subset of the 4645 * integer range. If there is the possibility that two values can 4646 * be unioned, this function returns %TRUE. 4647 * 4648 * Returns: %TRUE if there is a function allowing the two values to 4649 * be unioned. 4650 */ 4651 gboolean 4652 gst_value_can_union (const GValue * value1, const GValue * value2) 4653 { 4654 GstValueUnionInfo *union_info; 4655 guint i, len; 4656 4657 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 4658 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 4659 4660 len = gst_value_union_funcs->len; 4661 4662 for (i = 0; i < len; i++) { 4663 union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i); 4664 if (union_info->type1 == G_VALUE_TYPE (value1) && 4665 union_info->type2 == G_VALUE_TYPE (value2)) 4666 return TRUE; 4667 if (union_info->type1 == G_VALUE_TYPE (value2) && 4668 union_info->type2 == G_VALUE_TYPE (value1)) 4669 return TRUE; 4670 } 4671 4672 return FALSE; 4673 } 4674 4675 /** 4676 * gst_value_union: 4677 * @dest: (out caller-allocates): the destination value 4678 * @value1: a value to union 4679 * @value2: another value to union 4680 * 4681 * Creates a GValue corresponding to the union of @value1 and @value2. 4682 * 4683 * Returns: %TRUE if the union succeeded. 4684 */ 4685 gboolean 4686 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2) 4687 { 4688 const GstValueUnionInfo *union_info; 4689 guint i, len; 4690 GType type1, type2; 4691 4692 g_return_val_if_fail (dest != NULL, FALSE); 4693 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 4694 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 4695 g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2), 4696 FALSE); 4697 4698 len = gst_value_union_funcs->len; 4699 type1 = G_VALUE_TYPE (value1); 4700 type2 = G_VALUE_TYPE (value2); 4701 4702 for (i = 0; i < len; i++) { 4703 union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i); 4704 if (union_info->type1 == type1 && union_info->type2 == type2) { 4705 return union_info->func (dest, value1, value2); 4706 } 4707 if (union_info->type1 == type2 && union_info->type2 == type1) { 4708 return union_info->func (dest, value2, value1); 4709 } 4710 } 4711 4712 gst_value_list_concat (dest, value1, value2); 4713 return TRUE; 4714 } 4715 4716 /* gst_value_register_union_func: (skip) 4717 * @type1: a type to union 4718 * @type2: another type to union 4719 * @func: a function that implements creating a union between the two types 4720 * 4721 * Registers a union function that can create a union between #GValue items 4722 * of the type @type1 and @type2. 4723 * 4724 * Union functions should be registered at startup before any pipelines are 4725 * started, as gst_value_register_union_func() is not thread-safe and cannot 4726 * be used at the same time as gst_value_union() or gst_value_can_union(). 4727 */ 4728 static void 4729 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func) 4730 { 4731 GstValueUnionInfo union_info; 4732 4733 union_info.type1 = type1; 4734 union_info.type2 = type2; 4735 union_info.func = func; 4736 4737 g_array_append_val (gst_value_union_funcs, union_info); 4738 } 4739 4740 /* intersection */ 4741 4742 /** 4743 * gst_value_can_intersect: 4744 * @value1: a value to intersect 4745 * @value2: another value to intersect 4746 * 4747 * Determines if intersecting two values will produce a valid result. 4748 * Two values will produce a valid intersection if they have the same 4749 * type. 4750 * 4751 * Returns: %TRUE if the values can intersect 4752 */ 4753 gboolean 4754 gst_value_can_intersect (const GValue * value1, const GValue * value2) 4755 { 4756 GstValueIntersectInfo *intersect_info; 4757 guint i, len; 4758 GType type1, type2; 4759 4760 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 4761 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 4762 4763 type1 = G_VALUE_TYPE (value1); 4764 type2 = G_VALUE_TYPE (value2); 4765 4766 /* practically all GstValue types have a compare function (_can_compare=TRUE) 4767 * GstStructure and GstCaps have not, but are intersectable */ 4768 if (type1 == type2) 4769 return TRUE; 4770 4771 /* special cases */ 4772 if (type1 == GST_TYPE_LIST || type2 == GST_TYPE_LIST) 4773 return TRUE; 4774 4775 /* check registered intersect functions */ 4776 len = gst_value_intersect_funcs->len; 4777 for (i = 0; i < len; i++) { 4778 intersect_info = &g_array_index (gst_value_intersect_funcs, 4779 GstValueIntersectInfo, i); 4780 if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) || 4781 (intersect_info->type1 == type2 && intersect_info->type2 == type1)) 4782 return TRUE; 4783 } 4784 4785 return gst_value_can_compare_unchecked (value1, value2); 4786 } 4787 4788 /** 4789 * gst_value_intersect: 4790 * @dest: (out caller-allocates) (transfer full) (allow-none): 4791 * a uninitialized #GValue that will hold the calculated 4792 * intersection value. May be %NULL if the resulting set if not 4793 * needed. 4794 * @value1: a value to intersect 4795 * @value2: another value to intersect 4796 * 4797 * Calculates the intersection of two values. If the values have 4798 * a non-empty intersection, the value representing the intersection 4799 * is placed in @dest, unless %NULL. If the intersection is non-empty, 4800 * @dest is not modified. 4801 * 4802 * Returns: %TRUE if the intersection is non-empty 4803 */ 4804 gboolean 4805 gst_value_intersect (GValue * dest, const GValue * value1, 4806 const GValue * value2) 4807 { 4808 GstValueIntersectInfo *intersect_info; 4809 guint i, len; 4810 GType type1, type2; 4811 4812 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 4813 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 4814 4815 type1 = G_VALUE_TYPE (value1); 4816 type2 = G_VALUE_TYPE (value2); 4817 4818 /* special cases first */ 4819 if (type1 == GST_TYPE_LIST) 4820 return gst_value_intersect_list (dest, value1, value2); 4821 if (type2 == GST_TYPE_LIST) 4822 return gst_value_intersect_list (dest, value2, value1); 4823 4824 if (_gst_value_compare_nolist (value1, value2) == GST_VALUE_EQUAL) { 4825 if (dest) 4826 gst_value_init_and_copy (dest, value1); 4827 return TRUE; 4828 } 4829 4830 len = gst_value_intersect_funcs->len; 4831 for (i = 0; i < len; i++) { 4832 intersect_info = &g_array_index (gst_value_intersect_funcs, 4833 GstValueIntersectInfo, i); 4834 if (intersect_info->type1 == type1 && intersect_info->type2 == type2) { 4835 return intersect_info->func (dest, value1, value2); 4836 } 4837 if (intersect_info->type1 == type2 && intersect_info->type2 == type1) { 4838 return intersect_info->func (dest, value2, value1); 4839 } 4840 } 4841 return FALSE; 4842 } 4843 4844 4845 4846 /* gst_value_register_intersect_func: (skip) 4847 * @type1: the first type to intersect 4848 * @type2: the second type to intersect 4849 * @func: the intersection function 4850 * 4851 * Registers a function that is called to calculate the intersection 4852 * of the values having the types @type1 and @type2. 4853 * 4854 * Intersect functions should be registered at startup before any pipelines are 4855 * started, as gst_value_register_intersect_func() is not thread-safe and 4856 * cannot be used at the same time as gst_value_intersect() or 4857 * gst_value_can_intersect(). 4858 */ 4859 static void 4860 gst_value_register_intersect_func (GType type1, GType type2, 4861 GstValueIntersectFunc func) 4862 { 4863 GstValueIntersectInfo intersect_info; 4864 4865 intersect_info.type1 = type1; 4866 intersect_info.type2 = type2; 4867 intersect_info.func = func; 4868 4869 g_array_append_val (gst_value_intersect_funcs, intersect_info); 4870 } 4871 4872 4873 /* subtraction */ 4874 4875 /** 4876 * gst_value_subtract: 4877 * @dest: (out caller-allocates) (allow-none): the destination value 4878 * for the result if the subtraction is not empty. May be %NULL, 4879 * in which case the resulting set will not be computed, which can 4880 * give a fair speedup. 4881 * @minuend: the value to subtract from 4882 * @subtrahend: the value to subtract 4883 * 4884 * Subtracts @subtrahend from @minuend and stores the result in @dest. 4885 * Note that this means subtraction as in sets, not as in mathematics. 4886 * 4887 * Returns: %TRUE if the subtraction is not empty 4888 */ 4889 gboolean 4890 gst_value_subtract (GValue * dest, const GValue * minuend, 4891 const GValue * subtrahend) 4892 { 4893 GstValueSubtractInfo *info; 4894 guint i, len; 4895 GType mtype, stype; 4896 4897 g_return_val_if_fail (G_IS_VALUE (minuend), FALSE); 4898 g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE); 4899 4900 mtype = G_VALUE_TYPE (minuend); 4901 stype = G_VALUE_TYPE (subtrahend); 4902 4903 /* special cases first */ 4904 if (mtype == GST_TYPE_LIST) 4905 return gst_value_subtract_from_list (dest, minuend, subtrahend); 4906 if (stype == GST_TYPE_LIST) 4907 return gst_value_subtract_list (dest, minuend, subtrahend); 4908 4909 len = gst_value_subtract_funcs->len; 4910 for (i = 0; i < len; i++) { 4911 info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i); 4912 if (info->minuend == mtype && info->subtrahend == stype) { 4913 return info->func (dest, minuend, subtrahend); 4914 } 4915 } 4916 4917 if (_gst_value_compare_nolist (minuend, subtrahend) != GST_VALUE_EQUAL) { 4918 if (dest) 4919 gst_value_init_and_copy (dest, minuend); 4920 return TRUE; 4921 } 4922 4923 return FALSE; 4924 } 4925 4926 #if 0 4927 gboolean 4928 gst_value_subtract (GValue * dest, const GValue * minuend, 4929 const GValue * subtrahend) 4930 { 4931 gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend); 4932 4933 g_printerr ("\"%s\" - \"%s\" = \"%s\"\n", gst_value_serialize (minuend), 4934 gst_value_serialize (subtrahend), 4935 ret ? gst_value_serialize (dest) : "---"); 4936 return ret; 4937 } 4938 #endif 4939 4940 /** 4941 * gst_value_can_subtract: 4942 * @minuend: the value to subtract from 4943 * @subtrahend: the value to subtract 4944 * 4945 * Checks if it's possible to subtract @subtrahend from @minuend. 4946 * 4947 * Returns: %TRUE if a subtraction is possible 4948 */ 4949 gboolean 4950 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend) 4951 { 4952 GstValueSubtractInfo *info; 4953 guint i, len; 4954 GType mtype, stype; 4955 4956 g_return_val_if_fail (G_IS_VALUE (minuend), FALSE); 4957 g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE); 4958 4959 mtype = G_VALUE_TYPE (minuend); 4960 stype = G_VALUE_TYPE (subtrahend); 4961 4962 /* special cases */ 4963 if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST) 4964 return TRUE; 4965 4966 len = gst_value_subtract_funcs->len; 4967 for (i = 0; i < len; i++) { 4968 info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i); 4969 if (info->minuend == mtype && info->subtrahend == stype) 4970 return TRUE; 4971 } 4972 4973 return gst_value_can_compare_unchecked (minuend, subtrahend); 4974 } 4975 4976 /* gst_value_register_subtract_func: (skip) 4977 * @minuend_type: type of the minuend 4978 * @subtrahend_type: type of the subtrahend 4979 * @func: function to use 4980 * 4981 * Registers @func as a function capable of subtracting the values of 4982 * @subtrahend_type from values of @minuend_type. 4983 * 4984 * Subtract functions should be registered at startup before any pipelines are 4985 * started, as gst_value_register_subtract_func() is not thread-safe and 4986 * cannot be used at the same time as gst_value_subtract(). 4987 */ 4988 static void 4989 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type, 4990 GstValueSubtractFunc func) 4991 { 4992 GstValueSubtractInfo info; 4993 4994 g_return_if_fail (!gst_type_is_fixed (minuend_type) 4995 || !gst_type_is_fixed (subtrahend_type)); 4996 4997 info.minuend = minuend_type; 4998 info.subtrahend = subtrahend_type; 4999 info.func = func; 5000 5001 g_array_append_val (gst_value_subtract_funcs, info); 5002 } 5003 5004 /** 5005 * gst_value_register: 5006 * @table: structure containing functions to register 5007 * 5008 * Registers functions to perform calculations on #GValue items of a given 5009 * type. Each type can only be added once. 5010 */ 5011 void 5012 gst_value_register (const GstValueTable * table) 5013 { 5014 GstValueTable *found; 5015 5016 g_return_if_fail (table != NULL); 5017 5018 g_array_append_val (gst_value_table, *table); 5019 5020 found = gst_value_hash_lookup_type (table->type); 5021 if (found) 5022 g_warning ("adding type %s multiple times", g_type_name (table->type)); 5023 5024 /* FIXME: we're not really doing the const justice, we assume the table is 5025 * static */ 5026 gst_value_hash_add_type (table->type, table); 5027 } 5028 5029 /** 5030 * gst_value_init_and_copy: 5031 * @dest: (out caller-allocates): the target value 5032 * @src: the source value 5033 * 5034 * Initialises the target value to be of the same type as source and then copies 5035 * the contents from source to target. 5036 */ 5037 void 5038 gst_value_init_and_copy (GValue * dest, const GValue * src) 5039 { 5040 g_return_if_fail (G_IS_VALUE (src)); 5041 g_return_if_fail (dest != NULL); 5042 5043 g_value_init (dest, G_VALUE_TYPE (src)); 5044 g_value_copy (src, dest); 5045 } 5046 5047 /* move src into dest and clear src */ 5048 static void 5049 gst_value_move (GValue * dest, GValue * src) 5050 { 5051 g_assert (G_IS_VALUE (src)); 5052 g_assert (dest != NULL); 5053 5054 *dest = *src; 5055 memset (src, 0, sizeof (GValue)); 5056 } 5057 5058 /** 5059 * gst_value_serialize: 5060 * @value: a #GValue to serialize 5061 * 5062 * tries to transform the given @value into a string representation that allows 5063 * getting back this string later on using gst_value_deserialize(). 5064 * 5065 * Free-function: g_free 5066 * 5067 * Returns: (transfer full) (nullable): the serialization for @value 5068 * or %NULL if none exists 5069 */ 5070 gchar * 5071 gst_value_serialize (const GValue * value) 5072 { 5073 guint i, len; 5074 GValue s_val = { 0 }; 5075 GstValueTable *table, *best; 5076 gchar *s; 5077 GType type; 5078 5079 g_return_val_if_fail (G_IS_VALUE (value), NULL); 5080 5081 type = G_VALUE_TYPE (value); 5082 5083 best = gst_value_hash_lookup_type (type); 5084 5085 if (G_UNLIKELY (!best || !best->serialize)) { 5086 len = gst_value_table->len; 5087 best = NULL; 5088 for (i = 0; i < len; i++) { 5089 table = &g_array_index (gst_value_table, GstValueTable, i); 5090 if (table->serialize && g_type_is_a (type, table->type)) { 5091 if (!best || g_type_is_a (table->type, best->type)) 5092 best = table; 5093 } 5094 } 5095 } 5096 if (G_LIKELY (best)) 5097 return best->serialize (value); 5098 5099 g_value_init (&s_val, G_TYPE_STRING); 5100 if (g_value_transform (value, &s_val)) { 5101 s = gst_string_wrap (g_value_get_string (&s_val)); 5102 } else { 5103 s = NULL; 5104 } 5105 g_value_unset (&s_val); 5106 5107 return s; 5108 } 5109 5110 /** 5111 * gst_value_deserialize: 5112 * @dest: (out caller-allocates): #GValue to fill with contents of 5113 * deserialization 5114 * @src: string to deserialize 5115 * 5116 * Tries to deserialize a string into the type specified by the given GValue. 5117 * If the operation succeeds, %TRUE is returned, %FALSE otherwise. 5118 * 5119 * Returns: %TRUE on success 5120 */ 5121 gboolean 5122 gst_value_deserialize (GValue * dest, const gchar * src) 5123 { 5124 GstValueTable *table, *best; 5125 guint i, len; 5126 GType type; 5127 5128 g_return_val_if_fail (src != NULL, FALSE); 5129 g_return_val_if_fail (G_IS_VALUE (dest), FALSE); 5130 5131 type = G_VALUE_TYPE (dest); 5132 5133 best = gst_value_hash_lookup_type (type); 5134 if (G_UNLIKELY (!best || !best->deserialize)) { 5135 len = gst_value_table->len; 5136 best = NULL; 5137 for (i = 0; i < len; i++) { 5138 table = &g_array_index (gst_value_table, GstValueTable, i); 5139 if (table->deserialize && g_type_is_a (type, table->type)) { 5140 if (!best || g_type_is_a (table->type, best->type)) 5141 best = table; 5142 } 5143 } 5144 } 5145 if (G_LIKELY (best)) 5146 return best->deserialize (dest, src); 5147 5148 return FALSE; 5149 } 5150 5151 /** 5152 * gst_value_is_fixed: 5153 * @value: the #GValue to check 5154 * 5155 * Tests if the given GValue, if available in a GstStructure (or any other 5156 * container) contains a "fixed" (which means: one value) or an "unfixed" 5157 * (which means: multiple possible values, such as data lists or data 5158 * ranges) value. 5159 * 5160 * Returns: true if the value is "fixed". 5161 */ 5162 5163 gboolean 5164 gst_value_is_fixed (const GValue * value) 5165 { 5166 GType type; 5167 5168 g_return_val_if_fail (G_IS_VALUE (value), FALSE); 5169 5170 type = G_VALUE_TYPE (value); 5171 5172 /* the most common types are just basic plain glib types */ 5173 if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) { 5174 return TRUE; 5175 } 5176 5177 if (type == GST_TYPE_ARRAY) { 5178 gint size, n; 5179 const GValue *kid; 5180 5181 /* check recursively */ 5182 size = gst_value_array_get_size (value); 5183 for (n = 0; n < size; n++) { 5184 kid = gst_value_array_get_value (value, n); 5185 if (!gst_value_is_fixed (kid)) 5186 return FALSE; 5187 } 5188 return TRUE; 5189 } 5190 return gst_type_is_fixed (type); 5191 } 5192 5193 /** 5194 * gst_value_fixate: 5195 * @dest: the #GValue destination 5196 * @src: the #GValue to fixate 5197 * 5198 * Fixate @src into a new value @dest. 5199 * For ranges, the first element is taken. For lists and arrays, the 5200 * first item is fixated and returned. 5201 * If @src is already fixed, this function returns %FALSE. 5202 * 5203 * Returns: %TRUE if @dest contains a fixated version of @src. 5204 */ 5205 gboolean 5206 gst_value_fixate (GValue * dest, const GValue * src) 5207 { 5208 g_return_val_if_fail (G_IS_VALUE (src), FALSE); 5209 g_return_val_if_fail (dest != NULL, FALSE); 5210 5211 if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) { 5212 g_value_init (dest, G_TYPE_INT); 5213 g_value_set_int (dest, gst_value_get_int_range_min (src)); 5214 } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) { 5215 g_value_init (dest, G_TYPE_DOUBLE); 5216 g_value_set_double (dest, gst_value_get_double_range_min (src)); 5217 } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) { 5218 gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src)); 5219 } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) { 5220 GValue temp = { 0 }; 5221 5222 /* list could be empty */ 5223 if (gst_value_list_get_size (src) <= 0) 5224 return FALSE; 5225 5226 gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0)); 5227 5228 if (!gst_value_fixate (dest, &temp)) { 5229 gst_value_move (dest, &temp); 5230 } else { 5231 g_value_unset (&temp); 5232 } 5233 } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) { 5234 gboolean res = FALSE; 5235 guint n, len; 5236 5237 len = gst_value_array_get_size (src); 5238 g_value_init (dest, GST_TYPE_ARRAY); 5239 for (n = 0; n < len; n++) { 5240 GValue kid = { 0 }; 5241 const GValue *orig_kid = gst_value_array_get_value (src, n); 5242 5243 if (!gst_value_fixate (&kid, orig_kid)) 5244 gst_value_init_and_copy (&kid, orig_kid); 5245 else 5246 res = TRUE; 5247 _gst_value_array_append_and_take_value (dest, &kid); 5248 } 5249 5250 if (!res) 5251 g_value_unset (dest); 5252 5253 return res; 5254 } else { 5255 return FALSE; 5256 } 5257 return TRUE; 5258 } 5259 5260 5261 /************ 5262 * fraction * 5263 ************/ 5264 5265 /* helper functions */ 5266 static void 5267 gst_value_init_fraction (GValue * value) 5268 { 5269 value->data[0].v_int = 0; 5270 value->data[1].v_int = 1; 5271 } 5272 5273 static void 5274 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value) 5275 { 5276 dest_value->data[0].v_int = src_value->data[0].v_int; 5277 dest_value->data[1].v_int = src_value->data[1].v_int; 5278 } 5279 5280 static gchar * 5281 gst_value_collect_fraction (GValue * value, guint n_collect_values, 5282 GTypeCValue * collect_values, guint collect_flags) 5283 { 5284 if (n_collect_values != 2) 5285 return g_strdup_printf ("not enough value locations for `%s' passed", 5286 G_VALUE_TYPE_NAME (value)); 5287 if (collect_values[1].v_int == 0) 5288 return g_strdup_printf ("passed '0' as denominator for `%s'", 5289 G_VALUE_TYPE_NAME (value)); 5290 if (collect_values[0].v_int < -G_MAXINT) 5291 return 5292 g_strdup_printf 5293 ("passed value smaller than -G_MAXINT as numerator for `%s'", 5294 G_VALUE_TYPE_NAME (value)); 5295 if (collect_values[1].v_int < -G_MAXINT) 5296 return 5297 g_strdup_printf 5298 ("passed value smaller than -G_MAXINT as denominator for `%s'", 5299 G_VALUE_TYPE_NAME (value)); 5300 5301 gst_value_set_fraction (value, 5302 collect_values[0].v_int, collect_values[1].v_int); 5303 5304 return NULL; 5305 } 5306 5307 static gchar * 5308 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values, 5309 GTypeCValue * collect_values, guint collect_flags) 5310 { 5311 gint *numerator = collect_values[0].v_pointer; 5312 gint *denominator = collect_values[1].v_pointer; 5313 5314 if (!numerator) 5315 return g_strdup_printf ("numerator for `%s' passed as NULL", 5316 G_VALUE_TYPE_NAME (value)); 5317 if (!denominator) 5318 return g_strdup_printf ("denominator for `%s' passed as NULL", 5319 G_VALUE_TYPE_NAME (value)); 5320 5321 *numerator = value->data[0].v_int; 5322 *denominator = value->data[1].v_int; 5323 5324 return NULL; 5325 } 5326 5327 /** 5328 * gst_value_set_fraction: 5329 * @value: a GValue initialized to #GST_TYPE_FRACTION 5330 * @numerator: the numerator of the fraction 5331 * @denominator: the denominator of the fraction 5332 * 5333 * Sets @value to the fraction specified by @numerator over @denominator. 5334 * The fraction gets reduced to the smallest numerator and denominator, 5335 * and if necessary the sign is moved to the numerator. 5336 */ 5337 void 5338 gst_value_set_fraction (GValue * value, gint numerator, gint denominator) 5339 { 5340 gint gcd = 0; 5341 5342 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value)); 5343 g_return_if_fail (denominator != 0); 5344 g_return_if_fail (denominator >= -G_MAXINT); 5345 g_return_if_fail (numerator >= -G_MAXINT); 5346 5347 /* normalize sign */ 5348 if (denominator < 0) { 5349 numerator = -numerator; 5350 denominator = -denominator; 5351 } 5352 5353 /* check for reduction */ 5354 gcd = gst_util_greatest_common_divisor (numerator, denominator); 5355 if (gcd) { 5356 numerator /= gcd; 5357 denominator /= gcd; 5358 } 5359 5360 g_assert (denominator > 0); 5361 5362 value->data[0].v_int = numerator; 5363 value->data[1].v_int = denominator; 5364 } 5365 5366 /** 5367 * gst_value_get_fraction_numerator: 5368 * @value: a GValue initialized to #GST_TYPE_FRACTION 5369 * 5370 * Gets the numerator of the fraction specified by @value. 5371 * 5372 * Returns: the numerator of the fraction. 5373 */ 5374 gint 5375 gst_value_get_fraction_numerator (const GValue * value) 5376 { 5377 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0); 5378 5379 return value->data[0].v_int; 5380 } 5381 5382 /** 5383 * gst_value_get_fraction_denominator: 5384 * @value: a GValue initialized to #GST_TYPE_FRACTION 5385 * 5386 * Gets the denominator of the fraction specified by @value. 5387 * 5388 * Returns: the denominator of the fraction. 5389 */ 5390 gint 5391 gst_value_get_fraction_denominator (const GValue * value) 5392 { 5393 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1); 5394 5395 return value->data[1].v_int; 5396 } 5397 5398 /** 5399 * gst_value_fraction_multiply: 5400 * @product: a GValue initialized to #GST_TYPE_FRACTION 5401 * @factor1: a GValue initialized to #GST_TYPE_FRACTION 5402 * @factor2: a GValue initialized to #GST_TYPE_FRACTION 5403 * 5404 * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets 5405 * @product to the product of the two fractions. 5406 * 5407 * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise. 5408 */ 5409 gboolean 5410 gst_value_fraction_multiply (GValue * product, const GValue * factor1, 5411 const GValue * factor2) 5412 { 5413 gint n1, n2, d1, d2; 5414 gint res_n, res_d; 5415 5416 g_return_val_if_fail (product != NULL, FALSE); 5417 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE); 5418 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE); 5419 5420 n1 = factor1->data[0].v_int; 5421 n2 = factor2->data[0].v_int; 5422 d1 = factor1->data[1].v_int; 5423 d2 = factor2->data[1].v_int; 5424 5425 if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d)) 5426 return FALSE; 5427 5428 gst_value_set_fraction (product, res_n, res_d); 5429 5430 return TRUE; 5431 } 5432 5433 /** 5434 * gst_value_fraction_subtract: 5435 * @dest: a GValue initialized to #GST_TYPE_FRACTION 5436 * @minuend: a GValue initialized to #GST_TYPE_FRACTION 5437 * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION 5438 * 5439 * Subtracts the @subtrahend from the @minuend and sets @dest to the result. 5440 * 5441 * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise. 5442 */ 5443 gboolean 5444 gst_value_fraction_subtract (GValue * dest, 5445 const GValue * minuend, const GValue * subtrahend) 5446 { 5447 gint n1, n2, d1, d2; 5448 gint res_n, res_d; 5449 5450 g_return_val_if_fail (dest != NULL, FALSE); 5451 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE); 5452 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE); 5453 5454 n1 = minuend->data[0].v_int; 5455 n2 = subtrahend->data[0].v_int; 5456 d1 = minuend->data[1].v_int; 5457 d2 = subtrahend->data[1].v_int; 5458 5459 if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d)) 5460 return FALSE; 5461 gst_value_set_fraction (dest, res_n, res_d); 5462 5463 return TRUE; 5464 } 5465 5466 static gchar * 5467 gst_value_serialize_fraction (const GValue * value) 5468 { 5469 gint32 numerator = value->data[0].v_int; 5470 gint32 denominator = value->data[1].v_int; 5471 gboolean positive = TRUE; 5472 5473 /* get the sign and make components absolute */ 5474 if (numerator < 0) { 5475 numerator = -numerator; 5476 positive = !positive; 5477 } 5478 if (denominator < 0) { 5479 denominator = -denominator; 5480 positive = !positive; 5481 } 5482 5483 return g_strdup_printf ("%s%d/%d", 5484 positive ? "" : "-", numerator, denominator); 5485 } 5486 5487 static gboolean 5488 gst_value_deserialize_fraction (GValue * dest, const gchar * s) 5489 { 5490 gint num, den; 5491 gint num_chars; 5492 5493 if (G_UNLIKELY (s == NULL)) 5494 return FALSE; 5495 5496 if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest))) 5497 return FALSE; 5498 5499 if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) { 5500 if (s[num_chars] != 0) 5501 return FALSE; 5502 if (den == 0) 5503 return FALSE; 5504 5505 gst_value_set_fraction (dest, num, den); 5506 return TRUE; 5507 } else if (g_ascii_strcasecmp (s, "1/max") == 0) { 5508 gst_value_set_fraction (dest, 1, G_MAXINT); 5509 return TRUE; 5510 } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) { 5511 if (s[num_chars] != 0) 5512 return FALSE; 5513 gst_value_set_fraction (dest, num, 1); 5514 return TRUE; 5515 } else if (g_ascii_strcasecmp (s, "min") == 0) { 5516 gst_value_set_fraction (dest, -G_MAXINT, 1); 5517 return TRUE; 5518 } else if (g_ascii_strcasecmp (s, "max") == 0) { 5519 gst_value_set_fraction (dest, G_MAXINT, 1); 5520 return TRUE; 5521 } 5522 5523 return FALSE; 5524 } 5525 5526 static void 5527 gst_value_transform_fraction_string (const GValue * src_value, 5528 GValue * dest_value) 5529 { 5530 dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value); 5531 } 5532 5533 static void 5534 gst_value_transform_string_fraction (const GValue * src_value, 5535 GValue * dest_value) 5536 { 5537 if (!gst_value_deserialize_fraction (dest_value, 5538 src_value->data[0].v_pointer)) 5539 /* If the deserialize fails, ensure we leave the fraction in a 5540 * valid, if incorrect, state */ 5541 gst_value_set_fraction (dest_value, 0, 1); 5542 } 5543 5544 static void 5545 gst_value_transform_double_fraction (const GValue * src_value, 5546 GValue * dest_value) 5547 { 5548 gdouble src = g_value_get_double (src_value); 5549 gint n, d; 5550 5551 gst_util_double_to_fraction (src, &n, &d); 5552 gst_value_set_fraction (dest_value, n, d); 5553 } 5554 5555 static void 5556 gst_value_transform_float_fraction (const GValue * src_value, 5557 GValue * dest_value) 5558 { 5559 gfloat src = g_value_get_float (src_value); 5560 gint n, d; 5561 5562 gst_util_double_to_fraction (src, &n, &d); 5563 gst_value_set_fraction (dest_value, n, d); 5564 } 5565 5566 static void 5567 gst_value_transform_fraction_double (const GValue * src_value, 5568 GValue * dest_value) 5569 { 5570 dest_value->data[0].v_double = ((double) src_value->data[0].v_int) / 5571 ((double) src_value->data[1].v_int); 5572 } 5573 5574 static void 5575 gst_value_transform_fraction_float (const GValue * src_value, 5576 GValue * dest_value) 5577 { 5578 dest_value->data[0].v_float = ((float) src_value->data[0].v_int) / 5579 ((float) src_value->data[1].v_int); 5580 } 5581 5582 static gint 5583 gst_value_compare_fraction (const GValue * value1, const GValue * value2) 5584 { 5585 gint n1, n2; 5586 gint d1, d2; 5587 gint ret; 5588 5589 n1 = value1->data[0].v_int; 5590 n2 = value2->data[0].v_int; 5591 d1 = value1->data[1].v_int; 5592 d2 = value2->data[1].v_int; 5593 5594 /* fractions are reduced when set, so we can quickly see if they're equal */ 5595 if (n1 == n2 && d1 == d2) 5596 return GST_VALUE_EQUAL; 5597 5598 if (d1 == 0 && d2 == 0) 5599 return GST_VALUE_UNORDERED; 5600 else if (d1 == 0) 5601 return GST_VALUE_GREATER_THAN; 5602 else if (d2 == 0) 5603 return GST_VALUE_LESS_THAN; 5604 5605 ret = gst_util_fraction_compare (n1, d1, n2, d2); 5606 if (ret == -1) 5607 return GST_VALUE_LESS_THAN; 5608 else if (ret == 1) 5609 return GST_VALUE_GREATER_THAN; 5610 5611 /* Equality can't happen here because we check for that 5612 * first already */ 5613 g_return_val_if_reached (GST_VALUE_UNORDERED); 5614 } 5615 5616 /********* 5617 * GDate * 5618 *********/ 5619 5620 static gint 5621 gst_value_compare_date (const GValue * value1, const GValue * value2) 5622 { 5623 const GDate *date1 = (const GDate *) g_value_get_boxed (value1); 5624 const GDate *date2 = (const GDate *) g_value_get_boxed (value2); 5625 guint32 j1, j2; 5626 5627 if (date1 == date2) 5628 return GST_VALUE_EQUAL; 5629 5630 if ((date1 == NULL || !g_date_valid (date1)) 5631 && (date2 != NULL && g_date_valid (date2))) { 5632 return GST_VALUE_LESS_THAN; 5633 } 5634 5635 if ((date2 == NULL || !g_date_valid (date2)) 5636 && (date1 != NULL && g_date_valid (date1))) { 5637 return GST_VALUE_GREATER_THAN; 5638 } 5639 5640 if (date1 == NULL || date2 == NULL || !g_date_valid (date1) 5641 || !g_date_valid (date2)) { 5642 return GST_VALUE_UNORDERED; 5643 } 5644 5645 j1 = g_date_get_julian (date1); 5646 j2 = g_date_get_julian (date2); 5647 5648 if (j1 == j2) 5649 return GST_VALUE_EQUAL; 5650 else if (j1 < j2) 5651 return GST_VALUE_LESS_THAN; 5652 else 5653 return GST_VALUE_GREATER_THAN; 5654 } 5655 5656 static gchar * 5657 gst_value_serialize_date (const GValue * val) 5658 { 5659 const GDate *date = (const GDate *) g_value_get_boxed (val); 5660 5661 if (date == NULL || !g_date_valid (date)) 5662 return g_strdup ("9999-99-99"); 5663 5664 return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date), 5665 g_date_get_month (date), g_date_get_day (date)); 5666 } 5667 5668 static gboolean 5669 gst_value_deserialize_date (GValue * dest, const gchar * s) 5670 { 5671 guint year, month, day; 5672 5673 if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3) 5674 return FALSE; 5675 5676 if (!g_date_valid_dmy (day, month, year)) 5677 return FALSE; 5678 5679 g_value_take_boxed (dest, g_date_new_dmy (day, month, year)); 5680 return TRUE; 5681 } 5682 5683 /************* 5684 * GstDateTime * 5685 *************/ 5686 5687 static gint 5688 gst_value_compare_date_time (const GValue * value1, const GValue * value2) 5689 { 5690 const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1); 5691 const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2); 5692 5693 if (date1 == date2) 5694 return GST_VALUE_EQUAL; 5695 5696 if ((date1 == NULL) && (date2 != NULL)) { 5697 return GST_VALUE_LESS_THAN; 5698 } 5699 if ((date2 == NULL) && (date1 != NULL)) { 5700 return GST_VALUE_LESS_THAN; 5701 } 5702 5703 /* returns GST_VALUE_* */ 5704 return __gst_date_time_compare (date1, date2); 5705 } 5706 5707 static gchar * 5708 gst_value_serialize_date_time (const GValue * val) 5709 { 5710 GstDateTime *date = (GstDateTime *) g_value_get_boxed (val); 5711 5712 if (date == NULL) 5713 return g_strdup ("null"); 5714 5715 return __gst_date_time_serialize (date, TRUE); 5716 } 5717 5718 static gboolean 5719 gst_value_deserialize_date_time (GValue * dest, const gchar * s) 5720 { 5721 GstDateTime *datetime; 5722 5723 if (!s || strcmp (s, "null") == 0) { 5724 return FALSE; 5725 } 5726 5727 datetime = gst_date_time_new_from_iso8601_string (s); 5728 if (datetime != NULL) { 5729 g_value_take_boxed (dest, datetime); 5730 return TRUE; 5731 } 5732 GST_WARNING ("Failed to deserialize date time string '%s'", s); 5733 return FALSE; 5734 } 5735 5736 static void 5737 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value) 5738 { 5739 dest_value->data[0].v_pointer = gst_value_serialize_date (src_value); 5740 } 5741 5742 static void 5743 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value) 5744 { 5745 gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer); 5746 } 5747 5748 5749 /************ 5750 * bitmask * 5751 ************/ 5752 5753 /* helper functions */ 5754 static void 5755 gst_value_init_bitmask (GValue * value) 5756 { 5757 value->data[0].v_uint64 = 0; 5758 } 5759 5760 static void 5761 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value) 5762 { 5763 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; 5764 } 5765 5766 static gchar * 5767 gst_value_collect_bitmask (GValue * value, guint n_collect_values, 5768 GTypeCValue * collect_values, guint collect_flags) 5769 { 5770 if (n_collect_values != 1) 5771 return g_strdup_printf ("not enough value locations for `%s' passed", 5772 G_VALUE_TYPE_NAME (value)); 5773 5774 gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64); 5775 5776 return NULL; 5777 } 5778 5779 static gchar * 5780 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values, 5781 GTypeCValue * collect_values, guint collect_flags) 5782 { 5783 guint64 *bitmask = collect_values[0].v_pointer; 5784 5785 if (!bitmask) 5786 return g_strdup_printf ("value for `%s' passed as NULL", 5787 G_VALUE_TYPE_NAME (value)); 5788 5789 *bitmask = value->data[0].v_uint64; 5790 5791 return NULL; 5792 } 5793 5794 /** 5795 * gst_value_set_bitmask: 5796 * @value: a GValue initialized to #GST_TYPE_BITMASK 5797 * @bitmask: the bitmask 5798 * 5799 * Sets @value to the bitmask specified by @bitmask. 5800 */ 5801 void 5802 gst_value_set_bitmask (GValue * value, guint64 bitmask) 5803 { 5804 g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value)); 5805 5806 value->data[0].v_uint64 = bitmask; 5807 } 5808 5809 /** 5810 * gst_value_get_bitmask: 5811 * @value: a GValue initialized to #GST_TYPE_BITMASK 5812 * 5813 * Gets the bitmask specified by @value. 5814 * 5815 * Returns: the bitmask. 5816 */ 5817 guint64 5818 gst_value_get_bitmask (const GValue * value) 5819 { 5820 g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0); 5821 5822 return value->data[0].v_uint64; 5823 } 5824 5825 static gchar * 5826 gst_value_serialize_bitmask (const GValue * value) 5827 { 5828 guint64 bitmask = value->data[0].v_uint64; 5829 5830 return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask); 5831 } 5832 5833 static gboolean 5834 gst_value_deserialize_bitmask (GValue * dest, const gchar * s) 5835 { 5836 gchar *endptr = NULL; 5837 guint64 val; 5838 5839 if (G_UNLIKELY (s == NULL)) 5840 return FALSE; 5841 5842 if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest))) 5843 return FALSE; 5844 5845 val = g_ascii_strtoull (s, &endptr, 16); 5846 if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL)) 5847 return FALSE; 5848 if (val == 0 && endptr == s) 5849 return FALSE; 5850 5851 gst_value_set_bitmask (dest, val); 5852 5853 return TRUE; 5854 } 5855 5856 static void 5857 gst_value_transform_bitmask_string (const GValue * src_value, 5858 GValue * dest_value) 5859 { 5860 dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value); 5861 } 5862 5863 static void 5864 gst_value_transform_string_bitmask (const GValue * src_value, 5865 GValue * dest_value) 5866 { 5867 if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer)) 5868 gst_value_set_bitmask (dest_value, 0); 5869 } 5870 5871 static void 5872 gst_value_transform_uint64_bitmask (const GValue * src_value, 5873 GValue * dest_value) 5874 { 5875 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; 5876 } 5877 5878 static void 5879 gst_value_transform_bitmask_uint64 (const GValue * src_value, 5880 GValue * dest_value) 5881 { 5882 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; 5883 } 5884 5885 static gint 5886 gst_value_compare_bitmask (const GValue * value1, const GValue * value2) 5887 { 5888 guint64 v1, v2; 5889 5890 v1 = value1->data[0].v_uint64; 5891 v2 = value2->data[0].v_uint64; 5892 5893 if (v1 == v2) 5894 return GST_VALUE_EQUAL; 5895 5896 return GST_VALUE_UNORDERED; 5897 } 5898 5899 5900 /*********************** 5901 * GstAllocationParams * 5902 ***********************/ 5903 static gint 5904 gst_value_compare_allocation_params (const GValue * value1, 5905 const GValue * value2) 5906 { 5907 GstAllocationParams *v1, *v2; 5908 5909 v1 = value1->data[0].v_pointer; 5910 v2 = value2->data[0].v_pointer; 5911 5912 if (v1 == NULL && v1 == v2) 5913 return GST_VALUE_EQUAL; 5914 5915 if (v1 == NULL || v2 == NULL) 5916 return GST_VALUE_UNORDERED; 5917 5918 if (v1->flags == v2->flags && v1->align == v2->align && 5919 v1->prefix == v2->prefix && v1->padding == v2->padding) 5920 return GST_VALUE_EQUAL; 5921 5922 return GST_VALUE_UNORDERED; 5923 } 5924 5925 5926 /************ 5927 * GObject * 5928 ************/ 5929 5930 static gint 5931 gst_value_compare_object (const GValue * value1, const GValue * value2) 5932 { 5933 gpointer v1, v2; 5934 5935 v1 = value1->data[0].v_pointer; 5936 v2 = value2->data[0].v_pointer; 5937 5938 if (v1 == v2) 5939 return GST_VALUE_EQUAL; 5940 5941 return GST_VALUE_UNORDERED; 5942 } 5943 5944 static void 5945 gst_value_transform_object_string (const GValue * src_value, 5946 GValue * dest_value) 5947 { 5948 GstObject *obj; 5949 gchar *str; 5950 5951 obj = g_value_get_object (src_value); 5952 if (obj) { 5953 str = 5954 g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj), 5955 GST_OBJECT_NAME (obj)); 5956 } else { 5957 str = g_strdup ("NULL"); 5958 } 5959 5960 dest_value->data[0].v_pointer = str; 5961 } 5962 5963 static GTypeInfo _info = { 5964 0, 5965 NULL, 5966 NULL, 5967 NULL, 5968 NULL, 5969 NULL, 5970 0, 5971 0, 5972 NULL, 5973 NULL, 5974 }; 5975 5976 static GTypeFundamentalInfo _finfo = { 5977 0 5978 }; 5979 5980 #define FUNC_VALUE_GET_TYPE(type, name) \ 5981 GType _gst_ ## type ## _type = 0; \ 5982 \ 5983 GType gst_ ## type ## _get_type (void) \ 5984 { \ 5985 static volatile GType gst_ ## type ## _type = 0; \ 5986 \ 5987 if (g_once_init_enter (&gst_ ## type ## _type)) { \ 5988 GType _type; \ 5989 _info.value_table = & _gst_ ## type ## _value_table; \ 5990 _type = g_type_register_fundamental ( \ 5991 g_type_fundamental_next (), \ 5992 name, &_info, &_finfo, 0); \ 5993 _gst_ ## type ## _type = _type; \ 5994 g_once_init_leave(&gst_ ## type ## _type, _type); \ 5995 } \ 5996 \ 5997 return gst_ ## type ## _type; \ 5998 } 5999 6000 static const GTypeValueTable _gst_int_range_value_table = { 6001 gst_value_init_int_range, 6002 NULL, 6003 gst_value_copy_int_range, 6004 NULL, 6005 (char *) "ii", 6006 gst_value_collect_int_range, 6007 (char *) "pp", 6008 gst_value_lcopy_int_range 6009 }; 6010 6011 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange"); 6012 6013 static const GTypeValueTable _gst_int64_range_value_table = { 6014 gst_value_init_int64_range, 6015 gst_value_free_int64_range, 6016 gst_value_copy_int64_range, 6017 NULL, 6018 (char *) "qq", 6019 gst_value_collect_int64_range, 6020 (char *) "pp", 6021 gst_value_lcopy_int64_range 6022 }; 6023 6024 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range"); 6025 6026 static const GTypeValueTable _gst_double_range_value_table = { 6027 gst_value_init_double_range, 6028 NULL, 6029 gst_value_copy_double_range, 6030 NULL, 6031 (char *) "dd", 6032 gst_value_collect_double_range, 6033 (char *) "pp", 6034 gst_value_lcopy_double_range 6035 }; 6036 6037 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange"); 6038 6039 static const GTypeValueTable _gst_fraction_range_value_table = { 6040 gst_value_init_fraction_range, 6041 gst_value_free_fraction_range, 6042 gst_value_copy_fraction_range, 6043 NULL, 6044 (char *) "iiii", 6045 gst_value_collect_fraction_range, 6046 (char *) "pppp", 6047 gst_value_lcopy_fraction_range 6048 }; 6049 6050 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange"); 6051 6052 static const GTypeValueTable _gst_value_list_value_table = { 6053 gst_value_init_list_or_array, 6054 gst_value_free_list_or_array, 6055 gst_value_copy_list_or_array, 6056 gst_value_list_or_array_peek_pointer, 6057 (char *) "p", 6058 gst_value_collect_list_or_array, 6059 (char *) "p", 6060 gst_value_lcopy_list_or_array 6061 }; 6062 6063 FUNC_VALUE_GET_TYPE (value_list, "GstValueList"); 6064 6065 static const GTypeValueTable _gst_value_array_value_table = { 6066 gst_value_init_list_or_array, 6067 gst_value_free_list_or_array, 6068 gst_value_copy_list_or_array, 6069 gst_value_list_or_array_peek_pointer, 6070 (char *) "p", 6071 gst_value_collect_list_or_array, 6072 (char *) "p", 6073 gst_value_lcopy_list_or_array 6074 }; 6075 6076 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray"); 6077 6078 static const GTypeValueTable _gst_fraction_value_table = { 6079 gst_value_init_fraction, 6080 NULL, 6081 gst_value_copy_fraction, 6082 NULL, 6083 (char *) "ii", 6084 gst_value_collect_fraction, 6085 (char *) "pp", 6086 gst_value_lcopy_fraction 6087 }; 6088 6089 FUNC_VALUE_GET_TYPE (fraction, "GstFraction"); 6090 6091 static const GTypeValueTable _gst_bitmask_value_table = { 6092 gst_value_init_bitmask, 6093 NULL, 6094 gst_value_copy_bitmask, 6095 NULL, 6096 (char *) "q", 6097 gst_value_collect_bitmask, 6098 (char *) "p", 6099 gst_value_lcopy_bitmask 6100 }; 6101 6102 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask"); 6103 6104 GType 6105 gst_g_thread_get_type (void) 6106 { 6107 #if GLIB_CHECK_VERSION(2,35,3) 6108 return G_TYPE_THREAD; 6109 #else 6110 static volatile gsize type_id = 0; 6111 6112 if (g_once_init_enter (&type_id)) { 6113 GType tmp = 6114 g_boxed_type_register_static (g_intern_static_string ("GstGThread"), 6115 (GBoxedCopyFunc) g_thread_ref, 6116 (GBoxedFreeFunc) g_thread_unref); 6117 g_once_init_leave (&type_id, tmp); 6118 } 6119 6120 return type_id; 6121 #endif 6122 } 6123 6124 void 6125 _priv_gst_value_initialize (void) 6126 { 6127 gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable)); 6128 gst_value_hash = g_hash_table_new (NULL, NULL); 6129 gst_value_union_funcs = g_array_new (FALSE, FALSE, 6130 sizeof (GstValueUnionInfo)); 6131 gst_value_intersect_funcs = g_array_new (FALSE, FALSE, 6132 sizeof (GstValueIntersectInfo)); 6133 gst_value_subtract_funcs = g_array_new (FALSE, FALSE, 6134 sizeof (GstValueSubtractInfo)); 6135 6136 { 6137 static GstValueTable gst_value = { 6138 0, 6139 gst_value_compare_int_range, 6140 gst_value_serialize_int_range, 6141 gst_value_deserialize_int_range, 6142 }; 6143 6144 gst_value.type = gst_int_range_get_type (); 6145 gst_value_register (&gst_value); 6146 } 6147 6148 { 6149 static GstValueTable gst_value = { 6150 0, 6151 gst_value_compare_int64_range, 6152 gst_value_serialize_int64_range, 6153 gst_value_deserialize_int64_range, 6154 }; 6155 6156 gst_value.type = gst_int64_range_get_type (); 6157 gst_value_register (&gst_value); 6158 } 6159 6160 { 6161 static GstValueTable gst_value = { 6162 0, 6163 gst_value_compare_double_range, 6164 gst_value_serialize_double_range, 6165 gst_value_deserialize_double_range, 6166 }; 6167 6168 gst_value.type = gst_double_range_get_type (); 6169 gst_value_register (&gst_value); 6170 } 6171 6172 { 6173 static GstValueTable gst_value = { 6174 0, 6175 gst_value_compare_fraction_range, 6176 gst_value_serialize_fraction_range, 6177 gst_value_deserialize_fraction_range, 6178 }; 6179 6180 gst_value.type = gst_fraction_range_get_type (); 6181 gst_value_register (&gst_value); 6182 } 6183 6184 { 6185 static GstValueTable gst_value = { 6186 0, 6187 gst_value_compare_list, 6188 gst_value_serialize_list, 6189 gst_value_deserialize_list, 6190 }; 6191 6192 gst_value.type = gst_value_list_get_type (); 6193 gst_value_register (&gst_value); 6194 } 6195 6196 { 6197 static GstValueTable gst_value = { 6198 0, 6199 gst_value_compare_array, 6200 gst_value_serialize_array, 6201 gst_value_deserialize_array, 6202 }; 6203 6204 gst_value.type = gst_value_array_get_type (); 6205 gst_value_register (&gst_value); 6206 } 6207 6208 { 6209 #if 0 6210 static const GTypeValueTable value_table = { 6211 gst_value_init_buffer, 6212 NULL, 6213 gst_value_copy_buffer, 6214 NULL, 6215 "i", 6216 NULL, /*gst_value_collect_buffer, */ 6217 "p", 6218 NULL /*gst_value_lcopy_buffer */ 6219 }; 6220 #endif 6221 static GstValueTable gst_value = { 6222 0, 6223 gst_value_compare_buffer, 6224 gst_value_serialize_buffer, 6225 gst_value_deserialize_buffer, 6226 }; 6227 6228 gst_value.type = GST_TYPE_BUFFER; 6229 gst_value_register (&gst_value); 6230 } 6231 { 6232 static GstValueTable gst_value = { 6233 0, 6234 gst_value_compare_sample, 6235 gst_value_serialize_sample, 6236 gst_value_deserialize_sample, 6237 }; 6238 6239 gst_value.type = GST_TYPE_SAMPLE; 6240 gst_value_register (&gst_value); 6241 } 6242 { 6243 static GstValueTable gst_value = { 6244 0, 6245 gst_value_compare_fraction, 6246 gst_value_serialize_fraction, 6247 gst_value_deserialize_fraction, 6248 }; 6249 6250 gst_value.type = gst_fraction_get_type (); 6251 gst_value_register (&gst_value); 6252 } 6253 { 6254 static GstValueTable gst_value = { 6255 0, 6256 gst_value_compare_caps, 6257 gst_value_serialize_caps, 6258 gst_value_deserialize_caps, 6259 }; 6260 6261 gst_value.type = GST_TYPE_CAPS; 6262 gst_value_register (&gst_value); 6263 } 6264 { 6265 static GstValueTable gst_value = { 6266 0, 6267 NULL, 6268 gst_value_serialize_segment, 6269 gst_value_deserialize_segment, 6270 }; 6271 6272 gst_value.type = GST_TYPE_SEGMENT; 6273 gst_value_register (&gst_value); 6274 } 6275 { 6276 static GstValueTable gst_value = { 6277 0, 6278 NULL, 6279 gst_value_serialize_structure, 6280 gst_value_deserialize_structure, 6281 }; 6282 6283 gst_value.type = GST_TYPE_STRUCTURE; 6284 gst_value_register (&gst_value); 6285 } 6286 { 6287 static GstValueTable gst_value = { 6288 0, 6289 NULL, 6290 gst_value_serialize_caps_features, 6291 gst_value_deserialize_caps_features, 6292 }; 6293 6294 gst_value.type = GST_TYPE_CAPS_FEATURES; 6295 gst_value_register (&gst_value); 6296 } 6297 { 6298 static GstValueTable gst_value = { 6299 0, 6300 NULL, 6301 gst_value_serialize_tag_list, 6302 gst_value_deserialize_tag_list, 6303 }; 6304 6305 gst_value.type = GST_TYPE_TAG_LIST; 6306 gst_value_register (&gst_value); 6307 } 6308 { 6309 static GstValueTable gst_value = { 6310 0, 6311 gst_value_compare_date, 6312 gst_value_serialize_date, 6313 gst_value_deserialize_date, 6314 }; 6315 6316 gst_value.type = G_TYPE_DATE; 6317 gst_value_register (&gst_value); 6318 } 6319 { 6320 static GstValueTable gst_value = { 6321 0, 6322 gst_value_compare_date_time, 6323 gst_value_serialize_date_time, 6324 gst_value_deserialize_date_time, 6325 }; 6326 6327 gst_value.type = gst_date_time_get_type (); 6328 gst_value_register (&gst_value); 6329 } 6330 6331 { 6332 static GstValueTable gst_value = { 6333 0, 6334 gst_value_compare_bitmask, 6335 gst_value_serialize_bitmask, 6336 gst_value_deserialize_bitmask, 6337 }; 6338 6339 gst_value.type = gst_bitmask_get_type (); 6340 gst_value_register (&gst_value); 6341 } 6342 6343 { 6344 static GstValueTable gst_value = { 6345 0, 6346 gst_value_compare_allocation_params, 6347 NULL, 6348 NULL, 6349 }; 6350 6351 gst_value.type = gst_allocation_params_get_type (); 6352 gst_value_register (&gst_value); 6353 } 6354 6355 { 6356 static GstValueTable gst_value = { 6357 0, 6358 gst_value_compare_object, 6359 NULL, 6360 NULL, 6361 }; 6362 6363 gst_value.type = G_TYPE_OBJECT; 6364 gst_value_register (&gst_value); 6365 } 6366 6367 REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double); 6368 REGISTER_SERIALIZATION (G_TYPE_FLOAT, float); 6369 6370 REGISTER_SERIALIZATION (G_TYPE_STRING, string); 6371 REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean); 6372 REGISTER_SERIALIZATION (G_TYPE_ENUM, enum); 6373 6374 REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags); 6375 6376 REGISTER_SERIALIZATION (G_TYPE_INT, int); 6377 6378 REGISTER_SERIALIZATION (G_TYPE_INT64, int64); 6379 REGISTER_SERIALIZATION (G_TYPE_LONG, long); 6380 6381 REGISTER_SERIALIZATION (G_TYPE_UINT, uint); 6382 REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64); 6383 REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong); 6384 6385 REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar); 6386 6387 g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING, 6388 gst_value_transform_int_range_string); 6389 g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING, 6390 gst_value_transform_int64_range_string); 6391 g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING, 6392 gst_value_transform_double_range_string); 6393 g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING, 6394 gst_value_transform_fraction_range_string); 6395 g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING, 6396 gst_value_transform_list_string); 6397 g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING, 6398 gst_value_transform_array_string); 6399 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING, 6400 gst_value_transform_fraction_string); 6401 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION, 6402 gst_value_transform_string_fraction); 6403 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE, 6404 gst_value_transform_fraction_double); 6405 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT, 6406 gst_value_transform_fraction_float); 6407 g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION, 6408 gst_value_transform_double_fraction); 6409 g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION, 6410 gst_value_transform_float_fraction); 6411 g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING, 6412 gst_value_transform_date_string); 6413 g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE, 6414 gst_value_transform_string_date); 6415 g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING, 6416 gst_value_transform_object_string); 6417 g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64, 6418 gst_value_transform_bitmask_uint64); 6419 g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING, 6420 gst_value_transform_bitmask_string); 6421 g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK, 6422 gst_value_transform_uint64_bitmask); 6423 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK, 6424 gst_value_transform_string_bitmask); 6425 6426 gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE, 6427 gst_value_intersect_int_int_range); 6428 gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, 6429 gst_value_intersect_int_range_int_range); 6430 gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE, 6431 gst_value_intersect_int64_int64_range); 6432 gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE, 6433 gst_value_intersect_int64_range_int64_range); 6434 gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, 6435 gst_value_intersect_double_double_range); 6436 gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE, 6437 GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range); 6438 gst_value_register_intersect_func (GST_TYPE_ARRAY, 6439 GST_TYPE_ARRAY, gst_value_intersect_array); 6440 gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 6441 gst_value_intersect_fraction_fraction_range); 6442 gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE, 6443 GST_TYPE_FRACTION_RANGE, 6444 gst_value_intersect_fraction_range_fraction_range); 6445 6446 gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE, 6447 gst_value_subtract_int_int_range); 6448 gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT, 6449 gst_value_subtract_int_range_int); 6450 gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, 6451 gst_value_subtract_int_range_int_range); 6452 gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE, 6453 gst_value_subtract_int64_int64_range); 6454 gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64, 6455 gst_value_subtract_int64_range_int64); 6456 gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE, 6457 gst_value_subtract_int64_range_int64_range); 6458 gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, 6459 gst_value_subtract_double_double_range); 6460 gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE, 6461 gst_value_subtract_double_range_double); 6462 gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, 6463 GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range); 6464 gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 6465 gst_value_subtract_fraction_fraction_range); 6466 gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION, 6467 gst_value_subtract_fraction_range_fraction); 6468 gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, 6469 GST_TYPE_FRACTION_RANGE, 6470 gst_value_subtract_fraction_range_fraction_range); 6471 6472 /* see bug #317246, #64994, #65041 */ 6473 { 6474 volatile GType date_type = G_TYPE_DATE; 6475 6476 g_type_name (date_type); 6477 } 6478 6479 gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE, 6480 gst_value_union_int_int_range); 6481 gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, 6482 gst_value_union_int_range_int_range); 6483 6484 #if 0 6485 /* Implement these if needed */ 6486 gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 6487 gst_value_union_fraction_fraction_range); 6488 gst_value_register_union_func (GST_TYPE_FRACTION_RANGE, 6489 GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range); 6490 #endif 6491 }