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., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, 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 * Last reviewed on 2008-03-11 (0.10.18) 31 */ 32 33 #ifdef HAVE_CONFIG_H 34 #include "config.h" 35 #endif 36 #include <math.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <ctype.h> 41 42 #include "gst_private.h" 43 #include "glib-compat-private.h" 44 #include <gst/gst.h> 45 #include <gobject/gvaluecollector.h> 46 #include "gstutils.h" 47 48 typedef struct _GstValueUnionInfo GstValueUnionInfo; 49 struct _GstValueUnionInfo 50 { 51 GType type1; 52 GType type2; 53 GstValueUnionFunc func; 54 }; 55 56 typedef struct _GstValueIntersectInfo GstValueIntersectInfo; 57 struct _GstValueIntersectInfo 58 { 59 GType type1; 60 GType type2; 61 GstValueIntersectFunc func; 62 }; 63 64 typedef struct _GstValueSubtractInfo GstValueSubtractInfo; 65 struct _GstValueSubtractInfo 66 { 67 GType minuend; 68 GType subtrahend; 69 GstValueSubtractFunc func; 70 }; 71 72 #define FUNDAMENTAL_TYPE_ID_MAX \ 73 (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) 74 #define FUNDAMENTAL_TYPE_ID(type) \ 75 ((type) >> G_TYPE_FUNDAMENTAL_SHIFT) 76 77 #define VALUE_LIST_SIZE(v) (((GArray *) (v)->data[0].v_pointer)->len) 78 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index ((GArray *) (v)->data[0].v_pointer, GValue, (index))) 79 80 static GArray *gst_value_table; 81 static GHashTable *gst_value_hash; 82 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1]; 83 static GArray *gst_value_union_funcs; 84 static GArray *gst_value_intersect_funcs; 85 static GArray *gst_value_subtract_funcs; 86 87 /* Forward declarations */ 88 static gchar *gst_value_serialize_fraction (const GValue * value); 89 90 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1); 91 static gint gst_value_compare_with_func (const GValue * value1, 92 const GValue * value2, GstValueCompareFunc compare); 93 94 static gchar *gst_string_wrap (const gchar * s); 95 static gchar *gst_string_take_and_wrap (gchar * s); 96 static gchar *gst_string_unwrap (const gchar * s); 97 98 static inline GstValueTable * 99 gst_value_hash_lookup_type (GType type) 100 { 101 if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type))) 102 return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)]; 103 else 104 return g_hash_table_lookup (gst_value_hash, (gpointer) type); 105 } 106 107 static void 108 gst_value_hash_add_type (GType type, const GstValueTable * table) 109 { 110 if (G_TYPE_IS_FUNDAMENTAL (type)) 111 gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table; 112 113 g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table); 114 } 115 116 /******** 117 * list * 118 ********/ 119 120 /* two helper functions to serialize/stringify any type of list 121 * regular lists are done with { }, arrays with < > 122 */ 123 static gchar * 124 gst_value_serialize_any_list (const GValue * value, const gchar * begin, 125 const gchar * end) 126 { 127 guint i; 128 GArray *array = value->data[0].v_pointer; 129 GString *s; 130 GValue *v; 131 gchar *s_val; 132 guint alen = array->len; 133 134 /* estimate minimum string length to minimise re-allocs in GString */ 135 s = g_string_sized_new (2 + (6 * alen) + 2); 136 g_string_append (s, begin); 137 for (i = 0; i < alen; i++) { 138 v = &g_array_index (array, GValue, i); 139 s_val = gst_value_serialize (v); 140 g_string_append (s, s_val); 141 g_free (s_val); 142 if (i < alen - 1) { 143 g_string_append_len (s, ", ", 2); 144 } 145 } 146 g_string_append (s, end); 147 return g_string_free (s, FALSE); 148 } 149 150 static void 151 gst_value_transform_any_list_string (const GValue * src_value, 152 GValue * dest_value, const gchar * begin, const gchar * end) 153 { 154 GValue *list_value; 155 GArray *array; 156 GString *s; 157 guint i; 158 gchar *list_s; 159 guint alen; 160 161 array = src_value->data[0].v_pointer; 162 alen = array->len; 163 164 /* estimate minimum string length to minimise re-allocs in GString */ 165 s = g_string_sized_new (2 + (10 * alen) + 2); 166 g_string_append (s, begin); 167 for (i = 0; i < alen; i++) { 168 list_value = &g_array_index (array, GValue, i); 169 170 if (i != 0) { 171 g_string_append_len (s, ", ", 2); 172 } 173 list_s = g_strdup_value_contents (list_value); 174 g_string_append (s, list_s); 175 g_free (list_s); 176 } 177 g_string_append (s, end); 178 179 dest_value->data[0].v_pointer = g_string_free (s, FALSE); 180 } 181 182 /* 183 * helper function to see if a type is fixed. Is used internally here and 184 * there. Do not export, since it doesn't work for types where the content 185 * decides the fixedness (e.g. GST_TYPE_ARRAY). 186 */ 187 static gboolean 188 gst_type_is_fixed (GType type) 189 { 190 /* the basic int, string, double types */ 191 if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) { 192 return TRUE; 193 } 194 /* our fundamental types that are certainly not fixed */ 195 if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE || 196 type == GST_TYPE_INT64_RANGE || 197 type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) { 198 return FALSE; 199 } 200 /* other (boxed) types that are fixed */ 201 if (type == GST_TYPE_BUFFER) { 202 return TRUE; 203 } 204 /* heavy checks */ 205 if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <= 206 G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) { 207 return TRUE; 208 } 209 210 return FALSE; 211 } 212 213 /* GValue functions usable for both regular lists and arrays */ 214 static void 215 gst_value_init_list_or_array (GValue * value) 216 { 217 value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue)); 218 } 219 220 static GArray * 221 copy_garray_of_gstvalue (const GArray * src) 222 { 223 GArray *dest; 224 guint i, len; 225 226 len = src->len; 227 dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len); 228 g_array_set_size (dest, len); 229 for (i = 0; i < len; i++) { 230 gst_value_init_and_copy (&g_array_index (dest, GValue, i), 231 &g_array_index (src, GValue, i)); 232 } 233 234 return dest; 235 } 236 237 static void 238 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value) 239 { 240 dest_value->data[0].v_pointer = 241 copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer); 242 } 243 244 static void 245 gst_value_free_list_or_array (GValue * value) 246 { 247 guint i, len; 248 GArray *src = (GArray *) value->data[0].v_pointer; 249 len = src->len; 250 251 if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) { 252 for (i = 0; i < len; i++) { 253 g_value_unset (&g_array_index (src, GValue, i)); 254 } 255 g_array_free (src, TRUE); 256 } 257 } 258 259 static gpointer 260 gst_value_list_or_array_peek_pointer (const GValue * value) 261 { 262 return value->data[0].v_pointer; 263 } 264 265 static gchar * 266 gst_value_collect_list_or_array (GValue * value, guint n_collect_values, 267 GTypeCValue * collect_values, guint collect_flags) 268 { 269 if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { 270 value->data[0].v_pointer = collect_values[0].v_pointer; 271 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS; 272 } else { 273 value->data[0].v_pointer = 274 copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer); 275 } 276 return NULL; 277 } 278 279 static gchar * 280 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values, 281 GTypeCValue * collect_values, guint collect_flags) 282 { 283 GArray **dest = collect_values[0].v_pointer; 284 285 if (!dest) 286 return g_strdup_printf ("value location for `%s' passed as NULL", 287 G_VALUE_TYPE_NAME (value)); 288 if (!value->data[0].v_pointer) 289 return g_strdup_printf ("invalid value given for `%s'", 290 G_VALUE_TYPE_NAME (value)); 291 if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { 292 *dest = (GArray *) value->data[0].v_pointer; 293 } else { 294 *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer); 295 } 296 return NULL; 297 } 298 299 /** 300 * gst_value_list_append_value: 301 * @value: a #GValue of type #GST_TYPE_LIST 302 * @append_value: the value to append 303 * 304 * Appends @append_value to the GstValueList in @value. 305 */ 306 void 307 gst_value_list_append_value (GValue * value, const GValue * append_value) 308 { 309 GValue val = { 0, }; 310 311 g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); 312 g_return_if_fail (G_IS_VALUE (append_value)); 313 314 gst_value_init_and_copy (&val, append_value); 315 g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1); 316 } 317 318 #ifndef GSTREAMER_LITE 319 /** 320 * gst_value_list_prepend_value: 321 * @value: a #GValue of type #GST_TYPE_LIST 322 * @prepend_value: the value to prepend 323 * 324 * Prepends @prepend_value to the GstValueList in @value. 325 */ 326 void 327 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value) 328 { 329 GValue val = { 0, }; 330 331 g_return_if_fail (GST_VALUE_HOLDS_LIST (value)); 332 g_return_if_fail (G_IS_VALUE (prepend_value)); 333 334 gst_value_init_and_copy (&val, prepend_value); 335 g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1); 336 } 337 #endif // GSTREAMER_LITE 338 339 /** 340 * gst_value_list_concat: 341 * @dest: (out caller-allocates): an uninitialized #GValue to take the result 342 * @value1: a #GValue 343 * @value2: a #GValue 344 * 345 * Concatenates copies of @value1 and @value2 into a list. Values that are not 346 * of type #GST_TYPE_LIST are treated as if they were lists of length 1. 347 * @dest will be initialized to the type #GST_TYPE_LIST. 348 */ 349 void 350 gst_value_list_concat (GValue * dest, const GValue * value1, 351 const GValue * value2) 352 { 353 guint i, value1_length, value2_length; 354 GArray *array; 355 356 g_return_if_fail (dest != NULL); 357 g_return_if_fail (G_VALUE_TYPE (dest) == 0); 358 g_return_if_fail (G_IS_VALUE (value1)); 359 g_return_if_fail (G_IS_VALUE (value2)); 360 361 value1_length = 362 (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1); 363 value2_length = 364 (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1); 365 g_value_init (dest, GST_TYPE_LIST); 366 array = (GArray *) dest->data[0].v_pointer; 367 g_array_set_size (array, value1_length + value2_length); 368 369 if (GST_VALUE_HOLDS_LIST (value1)) { 370 for (i = 0; i < value1_length; i++) { 371 gst_value_init_and_copy (&g_array_index (array, GValue, i), 372 VALUE_LIST_GET_VALUE (value1, i)); 373 } 374 } else { 375 gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1); 376 } 377 378 if (GST_VALUE_HOLDS_LIST (value2)) { 379 for (i = 0; i < value2_length; i++) { 380 gst_value_init_and_copy (&g_array_index (array, GValue, 381 i + value1_length), VALUE_LIST_GET_VALUE (value2, i)); 382 } 383 } else { 384 gst_value_init_and_copy (&g_array_index (array, GValue, value1_length), 385 value2); 386 } 387 } 388 389 /** 390 * gst_value_list_merge: 391 * @dest: (out caller-allocates): an uninitialized #GValue to take the result 392 * @value1: a #GValue 393 * @value2: a #GValue 394 * 395 * Merges copies of @value1 and @value2. Values that are not 396 * of type #GST_TYPE_LIST are treated as if they were lists of length 1. 397 * 398 * The result will be put into @dest and will either be a list that will not 399 * contain any duplicates, or a non-list type (if @value1 and @value2 400 * were equal). 401 * 402 * Since: 0.10.32 403 */ 404 void 405 gst_value_list_merge (GValue * dest, const GValue * value1, 406 const GValue * value2) 407 { 408 guint i, j, k, value1_length, value2_length, skipped; 409 const GValue *src; 410 gboolean skip; 411 GArray *array; 412 413 g_return_if_fail (dest != NULL); 414 g_return_if_fail (G_VALUE_TYPE (dest) == 0); 415 g_return_if_fail (G_IS_VALUE (value1)); 416 g_return_if_fail (G_IS_VALUE (value2)); 417 418 value1_length = 419 (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1); 420 value2_length = 421 (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1); 422 g_value_init (dest, GST_TYPE_LIST); 423 array = (GArray *) dest->data[0].v_pointer; 424 g_array_set_size (array, value1_length + value2_length); 425 426 if (GST_VALUE_HOLDS_LIST (value1)) { 427 for (i = 0; i < value1_length; i++) { 428 gst_value_init_and_copy (&g_array_index (array, GValue, i), 429 VALUE_LIST_GET_VALUE (value1, i)); 430 } 431 } else { 432 gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1); 433 } 434 435 j = value1_length; 436 skipped = 0; 437 if (GST_VALUE_HOLDS_LIST (value2)) { 438 for (i = 0; i < value2_length; i++) { 439 skip = FALSE; 440 src = VALUE_LIST_GET_VALUE (value2, i); 441 for (k = 0; k < value1_length; k++) { 442 if (gst_value_compare (&g_array_index (array, GValue, k), 443 src) == GST_VALUE_EQUAL) { 444 skip = TRUE; 445 skipped++; 446 break; 447 } 448 } 449 if (!skip) { 450 gst_value_init_and_copy (&g_array_index (array, GValue, j), src); 451 j++; 452 } 453 } 454 } else { 455 skip = FALSE; 456 for (k = 0; k < value1_length; k++) { 457 if (gst_value_compare (&g_array_index (array, GValue, k), 458 value2) == GST_VALUE_EQUAL) { 459 skip = TRUE; 460 skipped++; 461 break; 462 } 463 } 464 if (!skip) { 465 gst_value_init_and_copy (&g_array_index (array, GValue, j), value2); 466 } 467 } 468 if (skipped) { 469 guint new_size = value1_length + (value2_length - skipped); 470 471 if (new_size > 1) { 472 /* shrink list */ 473 g_array_set_size (array, new_size); 474 } else { 475 GValue single_dest; 476 477 /* size is 1, take single value in list and make it new dest */ 478 single_dest = g_array_index (array, GValue, 0); 479 480 /* clean up old value allocations: must set array size to 0, because 481 * allocated values are not inited meaning g_value_unset() will not 482 * work on them */ 483 g_array_set_size (array, 0); 484 g_value_unset (dest); 485 486 /* the single value is our new result */ 487 *dest = single_dest; 488 } 489 } 490 } 491 492 /** 493 * gst_value_list_get_size: 494 * @value: a #GValue of type #GST_TYPE_LIST 495 * 496 * Gets the number of values contained in @value. 497 * 498 * Returns: the number of values 499 */ 500 guint 501 gst_value_list_get_size (const GValue * value) 502 { 503 g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0); 504 505 return ((GArray *) value->data[0].v_pointer)->len; 506 } 507 508 /** 509 * gst_value_list_get_value: 510 * @value: a #GValue of type #GST_TYPE_LIST 511 * @index: index of value to get from the list 512 * 513 * Gets the value that is a member of the list contained in @value and 514 * has the index @index. 515 * 516 * Returns: (transfer none): the value at the given index 517 */ 518 const GValue * 519 gst_value_list_get_value (const GValue * value, guint index) 520 { 521 g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL); 522 g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL); 523 524 return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, 525 GValue, index); 526 } 527 528 /** 529 * gst_value_array_append_value: 530 * @value: a #GValue of type #GST_TYPE_ARRAY 531 * @append_value: the value to append 532 * 533 * Appends @append_value to the GstValueArray in @value. 534 */ 535 void 536 gst_value_array_append_value (GValue * value, const GValue * append_value) 537 { 538 GValue val = { 0, }; 539 540 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); 541 g_return_if_fail (G_IS_VALUE (append_value)); 542 543 gst_value_init_and_copy (&val, append_value); 544 g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1); 545 } 546 547 #ifndef GSTREAMER_LITE 548 /** 549 * gst_value_array_prepend_value: 550 * @value: a #GValue of type #GST_TYPE_ARRAY 551 * @prepend_value: the value to prepend 552 * 553 * Prepends @prepend_value to the GstValueArray in @value. 554 */ 555 void 556 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value) 557 { 558 GValue val = { 0, }; 559 560 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value)); 561 g_return_if_fail (G_IS_VALUE (prepend_value)); 562 563 gst_value_init_and_copy (&val, prepend_value); 564 g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1); 565 } 566 #endif // GSTREAMER_LITE 567 568 /** 569 * gst_value_array_get_size: 570 * @value: a #GValue of type #GST_TYPE_ARRAY 571 * 572 * Gets the number of values contained in @value. 573 * 574 * Returns: the number of values 575 */ 576 guint 577 gst_value_array_get_size (const GValue * value) 578 { 579 g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0); 580 581 return ((GArray *) value->data[0].v_pointer)->len; 582 } 583 584 /** 585 * gst_value_array_get_value: 586 * @value: a #GValue of type #GST_TYPE_ARRAY 587 * @index: index of value to get from the array 588 * 589 * Gets the value that is a member of the array contained in @value and 590 * has the index @index. 591 * 592 * Returns: (transfer none): the value at the given index 593 */ 594 const GValue * 595 gst_value_array_get_value (const GValue * value, guint index) 596 { 597 g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL); 598 g_return_val_if_fail (index < gst_value_array_get_size (value), NULL); 599 600 return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, 601 GValue, index); 602 } 603 604 static void 605 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value) 606 { 607 gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }"); 608 } 609 610 static void 611 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value) 612 { 613 gst_value_transform_any_list_string (src_value, dest_value, "< ", " >"); 614 } 615 616 /* Do an unordered compare of the contents of a list */ 617 static gint 618 gst_value_compare_list (const GValue * value1, const GValue * value2) 619 { 620 guint i, j; 621 GArray *array1 = value1->data[0].v_pointer; 622 GArray *array2 = value2->data[0].v_pointer; 623 GValue *v1; 624 GValue *v2; 625 gint len, to_remove; 626 guint8 *removed; 627 GstValueCompareFunc compare; 628 629 /* get length and do initial length check. */ 630 len = array1->len; 631 if (len != array2->len) 632 return GST_VALUE_UNORDERED; 633 634 /* place to mark removed value indices of array2 */ 635 removed = g_newa (guint8, len); 636 memset (removed, 0, len); 637 to_remove = len; 638 639 /* loop over array1, all items should be in array2. When we find an 640 * item in array2, remove it from array2 by marking it as removed */ 641 for (i = 0; i < len; i++) { 642 v1 = &g_array_index (array1, GValue, i); 643 if ((compare = gst_value_get_compare_func (v1))) { 644 for (j = 0; j < len; j++) { 645 /* item is removed, we can skip it */ 646 if (removed[j]) 647 continue; 648 v2 = &g_array_index (array2, GValue, j); 649 if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) { 650 /* mark item as removed now that we found it in array2 and 651 * decrement the number of remaining items in array2. */ 652 removed[j] = 1; 653 to_remove--; 654 break; 655 } 656 } 657 /* item in array1 and not in array2, UNORDERED */ 658 if (j == len) 659 return GST_VALUE_UNORDERED; 660 } else 661 return GST_VALUE_UNORDERED; 662 } 663 /* if not all items were removed, array2 contained something not in array1 */ 664 if (to_remove != 0) 665 return GST_VALUE_UNORDERED; 666 667 /* arrays are equal */ 668 return GST_VALUE_EQUAL; 669 } 670 671 /* Perform an ordered comparison of the contents of an array */ 672 static gint 673 gst_value_compare_array (const GValue * value1, const GValue * value2) 674 { 675 guint i; 676 GArray *array1 = value1->data[0].v_pointer; 677 GArray *array2 = value2->data[0].v_pointer; 678 guint len = array1->len; 679 GValue *v1; 680 GValue *v2; 681 682 if (len != array2->len) 683 return GST_VALUE_UNORDERED; 684 685 for (i = 0; i < len; i++) { 686 v1 = &g_array_index (array1, GValue, i); 687 v2 = &g_array_index (array2, GValue, i); 688 if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL) 689 return GST_VALUE_UNORDERED; 690 } 691 692 return GST_VALUE_EQUAL; 693 } 694 695 static gchar * 696 gst_value_serialize_list (const GValue * value) 697 { 698 return gst_value_serialize_any_list (value, "{ ", " }"); 699 } 700 701 static gboolean 702 gst_value_deserialize_list (GValue * dest, const gchar * s) 703 { 704 g_warning ("gst_value_deserialize_list: unimplemented"); 705 return FALSE; 706 } 707 708 static gchar * 709 gst_value_serialize_array (const GValue * value) 710 { 711 return gst_value_serialize_any_list (value, "< ", " >"); 712 } 713 714 static gboolean 715 gst_value_deserialize_array (GValue * dest, const gchar * s) 716 { 717 g_warning ("gst_value_deserialize_array: unimplemented"); 718 return FALSE; 719 } 720 721 /********** 722 * fourcc * 723 **********/ 724 725 static void 726 gst_value_init_fourcc (GValue * value) 727 { 728 value->data[0].v_int = 0; 729 } 730 731 static void 732 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value) 733 { 734 dest_value->data[0].v_int = src_value->data[0].v_int; 735 } 736 737 static gchar * 738 gst_value_collect_fourcc (GValue * value, guint n_collect_values, 739 GTypeCValue * collect_values, guint collect_flags) 740 { 741 value->data[0].v_int = collect_values[0].v_int; 742 743 return NULL; 744 } 745 746 static gchar * 747 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values, 748 GTypeCValue * collect_values, guint collect_flags) 749 { 750 guint32 *fourcc_p = collect_values[0].v_pointer; 751 752 if (!fourcc_p) 753 return g_strdup_printf ("value location for `%s' passed as NULL", 754 G_VALUE_TYPE_NAME (value)); 755 756 *fourcc_p = value->data[0].v_int; 757 758 return NULL; 759 } 760 761 /** 762 * gst_value_set_fourcc: 763 * @value: a GValue initialized to #GST_TYPE_FOURCC 764 * @fourcc: the #guint32 fourcc to set 765 * 766 * Sets @value to @fourcc. 767 */ 768 void 769 gst_value_set_fourcc (GValue * value, guint32 fourcc) 770 { 771 g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value)); 772 773 value->data[0].v_int = fourcc; 774 } 775 776 /** 777 * gst_value_get_fourcc: 778 * @value: a GValue initialized to #GST_TYPE_FOURCC 779 * 780 * Gets the #guint32 fourcc contained in @value. 781 * 782 * Returns: the #guint32 fourcc contained in @value. 783 */ 784 guint32 785 gst_value_get_fourcc (const GValue * value) 786 { 787 g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0); 788 789 return value->data[0].v_int; 790 } 791 792 static void 793 gst_value_transform_fourcc_string (const GValue * src_value, 794 GValue * dest_value) 795 { 796 guint32 fourcc = src_value->data[0].v_int; 797 gchar fourcc_char[4]; 798 799 fourcc_char[0] = (fourcc >> 0) & 0xff; 800 fourcc_char[1] = (fourcc >> 8) & 0xff; 801 fourcc_char[2] = (fourcc >> 16) & 0xff; 802 fourcc_char[3] = (fourcc >> 24) & 0xff; 803 804 if ((g_ascii_isalnum (fourcc_char[0]) || fourcc_char[0] == ' ') && 805 (g_ascii_isalnum (fourcc_char[1]) || fourcc_char[1] == ' ') && 806 (g_ascii_isalnum (fourcc_char[2]) || fourcc_char[2] == ' ') && 807 (g_ascii_isalnum (fourcc_char[3]) || fourcc_char[3] == ' ')) { 808 dest_value->data[0].v_pointer = 809 g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); 810 } else { 811 dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc); 812 } 813 } 814 815 static gint 816 gst_value_compare_fourcc (const GValue * value1, const GValue * value2) 817 { 818 if (value2->data[0].v_int == value1->data[0].v_int) 819 return GST_VALUE_EQUAL; 820 return GST_VALUE_UNORDERED; 821 } 822 823 static gchar * 824 gst_value_serialize_fourcc (const GValue * value) 825 { 826 guint32 fourcc = value->data[0].v_int; 827 gchar fourcc_char[4]; 828 829 fourcc_char[0] = (fourcc >> 0) & 0xff; 830 fourcc_char[1] = (fourcc >> 8) & 0xff; 831 fourcc_char[2] = (fourcc >> 16) & 0xff; 832 fourcc_char[3] = (fourcc >> 24) & 0xff; 833 834 if ((g_ascii_isalnum (fourcc_char[0]) || fourcc_char[0] == ' ') && 835 (g_ascii_isalnum (fourcc_char[1]) || fourcc_char[1] == ' ') && 836 (g_ascii_isalnum (fourcc_char[2]) || fourcc_char[2] == ' ') && 837 (g_ascii_isalnum (fourcc_char[3]) || fourcc_char[3] == ' ')) { 838 return g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); 839 } else { 840 return g_strdup_printf ("0x%08x", fourcc); 841 } 842 } 843 844 static gboolean 845 gst_value_deserialize_fourcc (GValue * dest, const gchar * s) 846 { 847 gboolean ret = FALSE; 848 guint32 fourcc = 0; 849 gchar *end; 850 gint l = strlen (s); 851 852 if (l == 4) { 853 fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]); 854 ret = TRUE; 855 } else if (l == 3) { 856 fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], ' '); 857 ret = TRUE; 858 } else if (l == 2) { 859 fourcc = GST_MAKE_FOURCC (s[0], s[1], ' ', ' '); 860 ret = TRUE; 861 } else if (l == 1) { 862 fourcc = GST_MAKE_FOURCC (s[0], ' ', ' ', ' '); 863 ret = TRUE; 864 } else if (g_ascii_isdigit (*s)) { 865 fourcc = strtoul (s, &end, 0); 866 if (*end == 0) { 867 ret = TRUE; 868 } 869 } 870 gst_value_set_fourcc (dest, fourcc); 871 872 return ret; 873 } 874 875 /************* 876 * int range * 877 *************/ 878 879 static void 880 gst_value_init_int_range (GValue * value) 881 { 882 value->data[0].v_int = 0; 883 value->data[1].v_int = 0; 884 } 885 886 static void 887 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value) 888 { 889 dest_value->data[0].v_int = src_value->data[0].v_int; 890 dest_value->data[1].v_int = src_value->data[1].v_int; 891 } 892 893 static gchar * 894 gst_value_collect_int_range (GValue * value, guint n_collect_values, 895 GTypeCValue * collect_values, guint collect_flags) 896 { 897 if (n_collect_values != 2) 898 return g_strdup_printf ("not enough value locations for `%s' passed", 899 G_VALUE_TYPE_NAME (value)); 900 if (collect_values[0].v_int >= collect_values[1].v_int) 901 return g_strdup_printf ("range start is not smaller than end for `%s'", 902 G_VALUE_TYPE_NAME (value)); 903 904 value->data[0].v_int = collect_values[0].v_int; 905 value->data[1].v_int = collect_values[1].v_int; 906 907 return NULL; 908 } 909 910 static gchar * 911 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values, 912 GTypeCValue * collect_values, guint collect_flags) 913 { 914 guint32 *int_range_start = collect_values[0].v_pointer; 915 guint32 *int_range_end = collect_values[1].v_pointer; 916 917 if (!int_range_start) 918 return g_strdup_printf ("start value location for `%s' passed as NULL", 919 G_VALUE_TYPE_NAME (value)); 920 if (!int_range_end) 921 return g_strdup_printf ("end value location for `%s' passed as NULL", 922 G_VALUE_TYPE_NAME (value)); 923 924 *int_range_start = value->data[0].v_int; 925 *int_range_end = value->data[1].v_int; 926 927 return NULL; 928 } 929 930 /** 931 * gst_value_set_int_range: 932 * @value: a GValue initialized to GST_TYPE_INT_RANGE 933 * @start: the start of the range 934 * @end: the end of the range 935 * 936 * Sets @value to the range specified by @start and @end. 937 */ 938 void 939 gst_value_set_int_range (GValue * value, gint start, gint end) 940 { 941 g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value)); 942 g_return_if_fail (start < end); 943 944 value->data[0].v_int = start; 945 value->data[1].v_int = end; 946 } 947 948 /** 949 * gst_value_get_int_range_min: 950 * @value: a GValue initialized to GST_TYPE_INT_RANGE 951 * 952 * Gets the minimum of the range specified by @value. 953 * 954 * Returns: the minimum of the range 955 */ 956 gint 957 gst_value_get_int_range_min (const GValue * value) 958 { 959 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); 960 961 return value->data[0].v_int; 962 } 963 964 /** 965 * gst_value_get_int_range_max: 966 * @value: a GValue initialized to GST_TYPE_INT_RANGE 967 * 968 * Gets the maximum of the range specified by @value. 969 * 970 * Returns: the maxumum of the range 971 */ 972 gint 973 gst_value_get_int_range_max (const GValue * value) 974 { 975 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0); 976 977 return value->data[1].v_int; 978 } 979 980 static void 981 gst_value_transform_int_range_string (const GValue * src_value, 982 GValue * dest_value) 983 { 984 dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]", 985 (int) src_value->data[0].v_int, (int) src_value->data[1].v_int); 986 } 987 988 static gint 989 gst_value_compare_int_range (const GValue * value1, const GValue * value2) 990 { 991 if (value2->data[0].v_int == value1->data[0].v_int && 992 value2->data[1].v_int == value1->data[1].v_int) 993 return GST_VALUE_EQUAL; 994 return GST_VALUE_UNORDERED; 995 } 996 997 static gchar * 998 gst_value_serialize_int_range (const GValue * value) 999 { 1000 return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int, 1001 value->data[1].v_int); 1002 } 1003 1004 static gboolean 1005 gst_value_deserialize_int_range (GValue * dest, const gchar * s) 1006 { 1007 g_warning ("unimplemented"); 1008 return FALSE; 1009 } 1010 1011 /*************** 1012 * int64 range * 1013 ***************/ 1014 1015 static void 1016 gst_value_init_int64_range (GValue * value) 1017 { 1018 value->data[0].v_int64 = 0; 1019 value->data[1].v_int64 = 0; 1020 } 1021 1022 static void 1023 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value) 1024 { 1025 dest_value->data[0].v_int64 = src_value->data[0].v_int64; 1026 dest_value->data[1].v_int64 = src_value->data[1].v_int64; 1027 } 1028 1029 static gchar * 1030 gst_value_collect_int64_range (GValue * value, guint n_collect_values, 1031 GTypeCValue * collect_values, guint collect_flags) 1032 { 1033 if (n_collect_values != 2) 1034 return g_strdup_printf ("not enough value locations for `%s' passed", 1035 G_VALUE_TYPE_NAME (value)); 1036 if (collect_values[0].v_int64 >= collect_values[1].v_int64) 1037 return g_strdup_printf ("range start is not smaller than end for `%s'", 1038 G_VALUE_TYPE_NAME (value)); 1039 1040 value->data[0].v_int64 = collect_values[0].v_int64; 1041 value->data[1].v_int64 = collect_values[1].v_int64; 1042 1043 return NULL; 1044 } 1045 1046 static gchar * 1047 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values, 1048 GTypeCValue * collect_values, guint collect_flags) 1049 { 1050 guint64 *int_range_start = collect_values[0].v_pointer; 1051 guint64 *int_range_end = collect_values[1].v_pointer; 1052 1053 if (!int_range_start) 1054 return g_strdup_printf ("start value location for `%s' passed as NULL", 1055 G_VALUE_TYPE_NAME (value)); 1056 if (!int_range_end) 1057 return g_strdup_printf ("end value location for `%s' passed as NULL", 1058 G_VALUE_TYPE_NAME (value)); 1059 1060 *int_range_start = value->data[0].v_int64; 1061 *int_range_end = value->data[1].v_int64; 1062 1063 return NULL; 1064 } 1065 1066 /** 1067 * gst_value_set_int64_range: 1068 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1069 * @start: the start of the range 1070 * @end: the end of the range 1071 * 1072 * Sets @value to the range specified by @start and @end. 1073 * 1074 * Since: 0.10.31 1075 */ 1076 void 1077 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end) 1078 { 1079 g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value)); 1080 g_return_if_fail (start < end); 1081 1082 value->data[0].v_int64 = start; 1083 value->data[1].v_int64 = end; 1084 } 1085 1086 /** 1087 * gst_value_get_int64_range_min: 1088 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1089 * 1090 * Gets the minimum of the range specified by @value. 1091 * 1092 * Returns: the minimum of the range 1093 * 1094 * Since: 0.10.31 1095 */ 1096 gint64 1097 gst_value_get_int64_range_min (const GValue * value) 1098 { 1099 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); 1100 1101 return value->data[0].v_int64; 1102 } 1103 1104 /** 1105 * gst_value_get_int64_range_max: 1106 * @value: a GValue initialized to GST_TYPE_INT64_RANGE 1107 * 1108 * Gets the maximum of the range specified by @value. 1109 * 1110 * Returns: the maxumum of the range 1111 * 1112 * Since: 0.10.31 1113 */ 1114 gint64 1115 gst_value_get_int64_range_max (const GValue * value) 1116 { 1117 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0); 1118 1119 return value->data[1].v_int64; 1120 } 1121 1122 static void 1123 gst_value_transform_int64_range_string (const GValue * src_value, 1124 GValue * dest_value) 1125 { 1126 dest_value->data[0].v_pointer = 1127 g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]", 1128 src_value->data[0].v_int64, src_value->data[1].v_int64); 1129 } 1130 1131 static gint 1132 gst_value_compare_int64_range (const GValue * value1, const GValue * value2) 1133 { 1134 if (value2->data[0].v_int64 == value1->data[0].v_int64 && 1135 value2->data[1].v_int64 == value1->data[1].v_int64) 1136 return GST_VALUE_EQUAL; 1137 return GST_VALUE_UNORDERED; 1138 } 1139 1140 static gchar * 1141 gst_value_serialize_int64_range (const GValue * value) 1142 { 1143 return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]", 1144 value->data[0].v_int64, value->data[1].v_int64); 1145 } 1146 1147 static gboolean 1148 gst_value_deserialize_int64_range (GValue * dest, const gchar * s) 1149 { 1150 g_warning ("unimplemented"); 1151 return FALSE; 1152 } 1153 1154 /**************** 1155 * double range * 1156 ****************/ 1157 1158 static void 1159 gst_value_init_double_range (GValue * value) 1160 { 1161 value->data[0].v_double = 0; 1162 value->data[1].v_double = 0; 1163 } 1164 1165 static void 1166 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value) 1167 { 1168 dest_value->data[0].v_double = src_value->data[0].v_double; 1169 dest_value->data[1].v_double = src_value->data[1].v_double; 1170 } 1171 1172 static gchar * 1173 gst_value_collect_double_range (GValue * value, guint n_collect_values, 1174 GTypeCValue * collect_values, guint collect_flags) 1175 { 1176 if (n_collect_values != 2) 1177 return g_strdup_printf ("not enough value locations for `%s' passed", 1178 G_VALUE_TYPE_NAME (value)); 1179 if (collect_values[0].v_double >= collect_values[1].v_double) 1180 return g_strdup_printf ("range start is not smaller than end for `%s'", 1181 G_VALUE_TYPE_NAME (value)); 1182 1183 value->data[0].v_double = collect_values[0].v_double; 1184 value->data[1].v_double = collect_values[1].v_double; 1185 1186 return NULL; 1187 } 1188 1189 static gchar * 1190 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values, 1191 GTypeCValue * collect_values, guint collect_flags) 1192 { 1193 gdouble *double_range_start = collect_values[0].v_pointer; 1194 gdouble *double_range_end = collect_values[1].v_pointer; 1195 1196 if (!double_range_start) 1197 return g_strdup_printf ("start value location for `%s' passed as NULL", 1198 G_VALUE_TYPE_NAME (value)); 1199 if (!double_range_end) 1200 return g_strdup_printf ("end value location for `%s' passed as NULL", 1201 G_VALUE_TYPE_NAME (value)); 1202 1203 *double_range_start = value->data[0].v_double; 1204 *double_range_end = value->data[1].v_double; 1205 1206 return NULL; 1207 } 1208 1209 /** 1210 * gst_value_set_double_range: 1211 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE 1212 * @start: the start of the range 1213 * @end: the end of the range 1214 * 1215 * Sets @value to the range specified by @start and @end. 1216 */ 1217 void 1218 gst_value_set_double_range (GValue * value, gdouble start, gdouble end) 1219 { 1220 g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value)); 1221 g_return_if_fail (start < end); 1222 1223 value->data[0].v_double = start; 1224 value->data[1].v_double = end; 1225 } 1226 1227 /** 1228 * gst_value_get_double_range_min: 1229 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE 1230 * 1231 * Gets the minimum of the range specified by @value. 1232 * 1233 * Returns: the minimum of the range 1234 */ 1235 gdouble 1236 gst_value_get_double_range_min (const GValue * value) 1237 { 1238 g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0); 1239 1240 return value->data[0].v_double; 1241 } 1242 1243 /** 1244 * gst_value_get_double_range_max: 1245 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE 1246 * 1247 * Gets the maximum of the range specified by @value. 1248 * 1249 * Returns: the maxumum of the range 1250 */ 1251 gdouble 1252 gst_value_get_double_range_max (const GValue * value) 1253 { 1254 g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0); 1255 1256 return value->data[1].v_double; 1257 } 1258 1259 static void 1260 gst_value_transform_double_range_string (const GValue * src_value, 1261 GValue * dest_value) 1262 { 1263 gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE]; 1264 1265 dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]", 1266 g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE, 1267 src_value->data[0].v_double), 1268 g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE, 1269 src_value->data[1].v_double)); 1270 } 1271 1272 static gint 1273 gst_value_compare_double_range (const GValue * value1, const GValue * value2) 1274 { 1275 if (value2->data[0].v_double == value1->data[0].v_double && 1276 value2->data[0].v_double == value1->data[0].v_double) 1277 return GST_VALUE_EQUAL; 1278 return GST_VALUE_UNORDERED; 1279 } 1280 1281 static gchar * 1282 gst_value_serialize_double_range (const GValue * value) 1283 { 1284 gchar d1[G_ASCII_DTOSTR_BUF_SIZE]; 1285 gchar d2[G_ASCII_DTOSTR_BUF_SIZE]; 1286 1287 g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double); 1288 g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double); 1289 return g_strdup_printf ("[ %s, %s ]", d1, d2); 1290 } 1291 1292 static gboolean 1293 gst_value_deserialize_double_range (GValue * dest, const gchar * s) 1294 { 1295 g_warning ("unimplemented"); 1296 return FALSE; 1297 } 1298 1299 /**************** 1300 * fraction range * 1301 ****************/ 1302 1303 static void 1304 gst_value_init_fraction_range (GValue * value) 1305 { 1306 GValue *vals; 1307 GType ftype; 1308 1309 ftype = GST_TYPE_FRACTION; 1310 1311 value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue)); 1312 g_value_init (&vals[0], ftype); 1313 g_value_init (&vals[1], ftype); 1314 } 1315 1316 static void 1317 gst_value_free_fraction_range (GValue * value) 1318 { 1319 GValue *vals = (GValue *) value->data[0].v_pointer; 1320 1321 if (vals != NULL) { 1322 g_value_unset (&vals[0]); 1323 g_value_unset (&vals[1]); 1324 g_slice_free1 (2 * sizeof (GValue), vals); 1325 value->data[0].v_pointer = NULL; 1326 } 1327 } 1328 1329 static void 1330 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value) 1331 { 1332 GValue *vals = (GValue *) dest_value->data[0].v_pointer; 1333 GValue *src_vals = (GValue *) src_value->data[0].v_pointer; 1334 1335 if (vals == NULL) { 1336 gst_value_init_fraction_range (dest_value); 1337 vals = dest_value->data[0].v_pointer; 1338 } 1339 if (src_vals != NULL) { 1340 g_value_copy (&src_vals[0], &vals[0]); 1341 g_value_copy (&src_vals[1], &vals[1]); 1342 } 1343 } 1344 1345 static gchar * 1346 gst_value_collect_fraction_range (GValue * value, guint n_collect_values, 1347 GTypeCValue * collect_values, guint collect_flags) 1348 { 1349 GValue *vals = (GValue *) value->data[0].v_pointer; 1350 1351 if (n_collect_values != 4) 1352 return g_strdup_printf ("not enough value locations for `%s' passed", 1353 G_VALUE_TYPE_NAME (value)); 1354 if (collect_values[1].v_int == 0) 1355 return g_strdup_printf ("passed '0' as first denominator for `%s'", 1356 G_VALUE_TYPE_NAME (value)); 1357 if (collect_values[3].v_int == 0) 1358 return g_strdup_printf ("passed '0' as second denominator for `%s'", 1359 G_VALUE_TYPE_NAME (value)); 1360 if (gst_util_fraction_compare (collect_values[0].v_int, 1361 collect_values[1].v_int, collect_values[2].v_int, 1362 collect_values[3].v_int) >= 0) 1363 return g_strdup_printf ("range start is not smaller than end for `%s'", 1364 G_VALUE_TYPE_NAME (value)); 1365 1366 if (vals == NULL) { 1367 gst_value_init_fraction_range (value); 1368 vals = value->data[0].v_pointer; 1369 } 1370 1371 gst_value_set_fraction (&vals[0], collect_values[0].v_int, 1372 collect_values[1].v_int); 1373 gst_value_set_fraction (&vals[1], collect_values[2].v_int, 1374 collect_values[3].v_int); 1375 1376 return NULL; 1377 } 1378 1379 static gchar * 1380 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values, 1381 GTypeCValue * collect_values, guint collect_flags) 1382 { 1383 gint i; 1384 gint *dest_values[4]; 1385 GValue *vals = (GValue *) value->data[0].v_pointer; 1386 1387 if (G_UNLIKELY (n_collect_values != 4)) 1388 return g_strdup_printf ("not enough value locations for `%s' passed", 1389 G_VALUE_TYPE_NAME (value)); 1390 1391 for (i = 0; i < 4; i++) { 1392 if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) { 1393 return g_strdup_printf ("value location for `%s' passed as NULL", 1394 G_VALUE_TYPE_NAME (value)); 1395 } 1396 dest_values[i] = collect_values[i].v_pointer; 1397 } 1398 1399 if (G_UNLIKELY (vals == NULL)) { 1400 return g_strdup_printf ("Uninitialised `%s' passed", 1401 G_VALUE_TYPE_NAME (value)); 1402 } 1403 1404 dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]); 1405 dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]); 1406 dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]); 1407 dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]); 1408 return NULL; 1409 } 1410 1411 /** 1412 * gst_value_set_fraction_range: 1413 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1414 * @start: the start of the range (a GST_TYPE_FRACTION GValue) 1415 * @end: the end of the range (a GST_TYPE_FRACTION GValue) 1416 * 1417 * Sets @value to the range specified by @start and @end. 1418 */ 1419 void 1420 gst_value_set_fraction_range (GValue * value, const GValue * start, 1421 const GValue * end) 1422 { 1423 GValue *vals; 1424 1425 g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value)); 1426 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start)); 1427 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end)); 1428 g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int, 1429 start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0); 1430 1431 vals = (GValue *) value->data[0].v_pointer; 1432 if (vals == NULL) { 1433 gst_value_init_fraction_range (value); 1434 vals = value->data[0].v_pointer; 1435 } 1436 g_value_copy (start, &vals[0]); 1437 g_value_copy (end, &vals[1]); 1438 } 1439 1440 /** 1441 * gst_value_set_fraction_range_full: 1442 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1443 * @numerator_start: the numerator start of the range 1444 * @denominator_start: the denominator start of the range 1445 * @numerator_end: the numerator end of the range 1446 * @denominator_end: the denominator end of the range 1447 * 1448 * Sets @value to the range specified by @numerator_start/@denominator_start 1449 * and @numerator_end/@denominator_end. 1450 */ 1451 void 1452 gst_value_set_fraction_range_full (GValue * value, 1453 gint numerator_start, gint denominator_start, 1454 gint numerator_end, gint denominator_end) 1455 { 1456 GValue start = { 0 }; 1457 GValue end = { 0 }; 1458 1459 g_return_if_fail (value != NULL); 1460 g_return_if_fail (denominator_start != 0); 1461 g_return_if_fail (denominator_end != 0); 1462 g_return_if_fail (gst_util_fraction_compare (numerator_start, 1463 denominator_start, numerator_end, denominator_end) < 0); 1464 1465 g_value_init (&start, GST_TYPE_FRACTION); 1466 g_value_init (&end, GST_TYPE_FRACTION); 1467 1468 gst_value_set_fraction (&start, numerator_start, denominator_start); 1469 gst_value_set_fraction (&end, numerator_end, denominator_end); 1470 gst_value_set_fraction_range (value, &start, &end); 1471 1472 g_value_unset (&start); 1473 g_value_unset (&end); 1474 } 1475 1476 /** 1477 * gst_value_get_fraction_range_min: 1478 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1479 * 1480 * Gets the minimum of the range specified by @value. 1481 * 1482 * Returns: the minimum of the range 1483 */ 1484 const GValue * 1485 gst_value_get_fraction_range_min (const GValue * value) 1486 { 1487 GValue *vals; 1488 1489 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL); 1490 1491 vals = (GValue *) value->data[0].v_pointer; 1492 if (vals != NULL) { 1493 return &vals[0]; 1494 } 1495 1496 return NULL; 1497 } 1498 1499 /** 1500 * gst_value_get_fraction_range_max: 1501 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE 1502 * 1503 * Gets the maximum of the range specified by @value. 1504 * 1505 * Returns: the maximum of the range 1506 */ 1507 const GValue * 1508 gst_value_get_fraction_range_max (const GValue * value) 1509 { 1510 GValue *vals; 1511 1512 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL); 1513 1514 vals = (GValue *) value->data[0].v_pointer; 1515 if (vals != NULL) { 1516 return &vals[1]; 1517 } 1518 1519 return NULL; 1520 } 1521 1522 static gchar * 1523 gst_value_serialize_fraction_range (const GValue * value) 1524 { 1525 GValue *vals = (GValue *) value->data[0].v_pointer; 1526 gchar *retval; 1527 1528 if (vals == NULL) { 1529 retval = g_strdup ("[ 0/1, 0/1 ]"); 1530 } else { 1531 gchar *start, *end; 1532 1533 start = gst_value_serialize_fraction (&vals[0]); 1534 end = gst_value_serialize_fraction (&vals[1]); 1535 1536 retval = g_strdup_printf ("[ %s, %s ]", start, end); 1537 g_free (start); 1538 g_free (end); 1539 } 1540 1541 return retval; 1542 } 1543 1544 static void 1545 gst_value_transform_fraction_range_string (const GValue * src_value, 1546 GValue * dest_value) 1547 { 1548 dest_value->data[0].v_pointer = 1549 gst_value_serialize_fraction_range (src_value); 1550 } 1551 1552 static gint 1553 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2) 1554 { 1555 GValue *vals1, *vals2; 1556 GstValueCompareFunc compare; 1557 1558 if (value2->data[0].v_pointer == value1->data[0].v_pointer) 1559 return GST_VALUE_EQUAL; /* Only possible if both are NULL */ 1560 1561 if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL) 1562 return GST_VALUE_UNORDERED; 1563 1564 vals1 = (GValue *) value1->data[0].v_pointer; 1565 vals2 = (GValue *) value2->data[0].v_pointer; 1566 if ((compare = gst_value_get_compare_func (&vals1[0]))) { 1567 if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) == 1568 GST_VALUE_EQUAL && 1569 gst_value_compare_with_func (&vals1[1], &vals2[1], compare) == 1570 GST_VALUE_EQUAL) 1571 return GST_VALUE_EQUAL; 1572 } 1573 return GST_VALUE_UNORDERED; 1574 } 1575 1576 static gboolean 1577 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s) 1578 { 1579 g_warning ("unimplemented"); 1580 return FALSE; 1581 } 1582 1583 /*********** 1584 * GstCaps * 1585 ***********/ 1586 1587 /** 1588 * gst_value_set_caps: 1589 * @value: a GValue initialized to GST_TYPE_CAPS 1590 * @caps: (transfer none): the caps to set the value to 1591 * 1592 * Sets the contents of @value to @caps. A reference to the 1593 * provided @caps will be taken by the @value. 1594 */ 1595 void 1596 gst_value_set_caps (GValue * value, const GstCaps * caps) 1597 { 1598 g_return_if_fail (G_IS_VALUE (value)); 1599 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS); 1600 g_return_if_fail (caps == NULL || GST_IS_CAPS (caps)); 1601 1602 g_value_set_boxed (value, caps); 1603 } 1604 1605 /** 1606 * gst_value_get_caps: 1607 * @value: a GValue initialized to GST_TYPE_CAPS 1608 * 1609 * Gets the contents of @value. The reference count of the returned 1610 * #GstCaps will not be modified, therefore the caller must take one 1611 * before getting rid of the @value. 1612 * 1613 * Returns: (transfer none): the contents of @value 1614 */ 1615 const GstCaps * 1616 gst_value_get_caps (const GValue * value) 1617 { 1618 g_return_val_if_fail (G_IS_VALUE (value), NULL); 1619 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL); 1620 1621 return (GstCaps *) g_value_get_boxed (value); 1622 } 1623 1624 static gchar * 1625 gst_value_serialize_caps (const GValue * value) 1626 { 1627 GstCaps *caps = g_value_get_boxed (value); 1628 1629 return gst_caps_to_string (caps); 1630 } 1631 1632 static gboolean 1633 gst_value_deserialize_caps (GValue * dest, const gchar * s) 1634 { 1635 GstCaps *caps; 1636 1637 caps = gst_caps_from_string (s); 1638 1639 if (caps) { 1640 g_value_take_boxed (dest, caps); 1641 return TRUE; 1642 } 1643 return FALSE; 1644 } 1645 1646 /**************** 1647 * GstStructure * 1648 ****************/ 1649 1650 /** 1651 * gst_value_set_structure: 1652 * @value: a GValue initialized to GST_TYPE_STRUCTURE 1653 * @structure: the structure to set the value to 1654 * 1655 * Sets the contents of @value to @structure. The actual 1656 * 1657 * Since: 0.10.15 1658 */ 1659 void 1660 gst_value_set_structure (GValue * value, const GstStructure * structure) 1661 { 1662 g_return_if_fail (G_IS_VALUE (value)); 1663 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE); 1664 g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure)); 1665 1666 g_value_set_boxed (value, structure); 1667 } 1668 1669 /** 1670 * gst_value_get_structure: 1671 * @value: a GValue initialized to GST_TYPE_STRUCTURE 1672 * 1673 * Gets the contents of @value. 1674 * 1675 * Returns: (transfer none): the contents of @value 1676 * 1677 * Since: 0.10.15 1678 */ 1679 const GstStructure * 1680 gst_value_get_structure (const GValue * value) 1681 { 1682 g_return_val_if_fail (G_IS_VALUE (value), NULL); 1683 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL); 1684 1685 return (GstStructure *) g_value_get_boxed (value); 1686 } 1687 1688 static gchar * 1689 gst_value_serialize_structure (const GValue * value) 1690 { 1691 GstStructure *structure = g_value_get_boxed (value); 1692 1693 return gst_string_take_and_wrap (gst_structure_to_string (structure)); 1694 } 1695 1696 static gboolean 1697 gst_value_deserialize_structure (GValue * dest, const gchar * s) 1698 { 1699 GstStructure *structure; 1700 1701 if (*s != '"') { 1702 structure = gst_structure_from_string (s, NULL); 1703 } else { 1704 gchar *str = gst_string_unwrap (s); 1705 1706 if (G_UNLIKELY (!str)) 1707 return FALSE; 1708 1709 structure = gst_structure_from_string (str, NULL); 1710 g_free (str); 1711 } 1712 1713 if (G_LIKELY (structure)) { 1714 g_value_take_boxed (dest, structure); 1715 return TRUE; 1716 } 1717 return FALSE; 1718 } 1719 1720 /************* 1721 * GstBuffer * 1722 *************/ 1723 1724 static gint 1725 gst_value_compare_buffer (const GValue * value1, const GValue * value2) 1726 { 1727 GstBuffer *buf1 = GST_BUFFER (gst_value_get_mini_object (value1)); 1728 GstBuffer *buf2 = GST_BUFFER (gst_value_get_mini_object (value2)); 1729 1730 if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2)) 1731 return GST_VALUE_UNORDERED; 1732 if (GST_BUFFER_SIZE (buf1) == 0) 1733 return GST_VALUE_EQUAL; 1734 g_assert (GST_BUFFER_DATA (buf1)); 1735 g_assert (GST_BUFFER_DATA (buf2)); 1736 if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2), 1737 GST_BUFFER_SIZE (buf1)) == 0) 1738 return GST_VALUE_EQUAL; 1739 1740 return GST_VALUE_UNORDERED; 1741 } 1742 1743 static gchar * 1744 gst_value_serialize_buffer (const GValue * value) 1745 { 1746 guint8 *data; 1747 gint i; 1748 gint size; 1749 gchar *string; 1750 GstBuffer *buffer; 1751 1752 buffer = gst_value_get_buffer (value); 1753 if (buffer == NULL) 1754 return NULL; 1755 1756 data = GST_BUFFER_DATA (buffer); 1757 size = GST_BUFFER_SIZE (buffer); 1758 1759 string = g_malloc (size * 2 + 1); 1760 for (i = 0; i < size; i++) { 1761 sprintf (string + i * 2, "%02x", data[i]); 1762 } 1763 string[size * 2] = 0; 1764 1765 return string; 1766 } 1767 1768 static gboolean 1769 gst_value_deserialize_buffer (GValue * dest, const gchar * s) 1770 { 1771 GstBuffer *buffer; 1772 gint len; 1773 gchar ts[3]; 1774 guint8 *data; 1775 gint i; 1776 1777 len = strlen (s); 1778 if (len & 1) 1779 goto wrong_length; 1780 1781 buffer = gst_buffer_new_and_alloc (len / 2); 1782 data = GST_BUFFER_DATA (buffer); 1783 for (i = 0; i < len / 2; i++) { 1784 if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) 1785 goto wrong_char; 1786 1787 ts[0] = s[i * 2 + 0]; 1788 ts[1] = s[i * 2 + 1]; 1789 ts[2] = 0; 1790 1791 data[i] = (guint8) strtoul (ts, NULL, 16); 1792 } 1793 1794 gst_value_take_buffer (dest, buffer); 1795 1796 return TRUE; 1797 1798 /* ERRORS */ 1799 wrong_length: 1800 { 1801 return FALSE; 1802 } 1803 wrong_char: 1804 { 1805 gst_buffer_unref (buffer); 1806 return FALSE; 1807 } 1808 } 1809 1810 1811 /*********** 1812 * boolean * 1813 ***********/ 1814 1815 static gint 1816 gst_value_compare_boolean (const GValue * value1, const GValue * value2) 1817 { 1818 if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0)) 1819 return GST_VALUE_EQUAL; 1820 return GST_VALUE_UNORDERED; 1821 } 1822 1823 static gchar * 1824 gst_value_serialize_boolean (const GValue * value) 1825 { 1826 if (value->data[0].v_int) { 1827 return g_strdup ("true"); 1828 } 1829 return g_strdup ("false"); 1830 } 1831 1832 static gboolean 1833 gst_value_deserialize_boolean (GValue * dest, const gchar * s) 1834 { 1835 gboolean ret = FALSE; 1836 1837 if (g_ascii_strcasecmp (s, "true") == 0 || 1838 g_ascii_strcasecmp (s, "yes") == 0 || 1839 g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) { 1840 g_value_set_boolean (dest, TRUE); 1841 ret = TRUE; 1842 } else if (g_ascii_strcasecmp (s, "false") == 0 || 1843 g_ascii_strcasecmp (s, "no") == 0 || 1844 g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) { 1845 g_value_set_boolean (dest, FALSE); 1846 ret = TRUE; 1847 } 1848 1849 return ret; 1850 } 1851 1852 #define CREATE_SERIALIZATION_START(_type,_macro) \ 1853 static gint \ 1854 gst_value_compare_ ## _type \ 1855 (const GValue * value1, const GValue * value2) \ 1856 { \ 1857 g ## _type val1 = g_value_get_ ## _type (value1); \ 1858 g ## _type val2 = g_value_get_ ## _type (value2); \ 1859 if (val1 > val2) \ 1860 return GST_VALUE_GREATER_THAN; \ 1861 if (val1 < val2) \ 1862 return GST_VALUE_LESS_THAN; \ 1863 return GST_VALUE_EQUAL; \ 1864 } \ 1865 \ 1866 static gchar * \ 1867 gst_value_serialize_ ## _type (const GValue * value) \ 1868 { \ 1869 GValue val = { 0, }; \ 1870 g_value_init (&val, G_TYPE_STRING); \ 1871 if (!g_value_transform (value, &val)) \ 1872 g_assert_not_reached (); \ 1873 /* NO_COPY_MADNESS!!! */ \ 1874 return (char *) g_value_get_string (&val); \ 1875 } 1876 1877 /* deserialize the given s into to as a gint64. 1878 * check if the result is actually storeable in the given size number of 1879 * bytes. 1880 */ 1881 static gboolean 1882 gst_value_deserialize_int_helper (gint64 * to, const gchar * s, 1883 gint64 min, gint64 max, gint size) 1884 { 1885 gboolean ret = FALSE; 1886 gchar *end; 1887 gint64 mask = -1; 1888 1889 errno = 0; 1890 *to = g_ascii_strtoull (s, &end, 0); 1891 /* a range error is a definitive no-no */ 1892 if (errno == ERANGE) { 1893 return FALSE; 1894 } 1895 1896 if (*end == 0) { 1897 ret = TRUE; 1898 } else { 1899 if (g_ascii_strcasecmp (s, "little_endian") == 0) { 1900 *to = G_LITTLE_ENDIAN; 1901 ret = TRUE; 1902 } else if (g_ascii_strcasecmp (s, "big_endian") == 0) { 1903 *to = G_BIG_ENDIAN; 1904 ret = TRUE; 1905 } else if (g_ascii_strcasecmp (s, "byte_order") == 0) { 1906 *to = G_BYTE_ORDER; 1907 ret = TRUE; 1908 } else if (g_ascii_strcasecmp (s, "min") == 0) { 1909 *to = min; 1910 ret = TRUE; 1911 } else if (g_ascii_strcasecmp (s, "max") == 0) { 1912 *to = max; 1913 ret = TRUE; 1914 } 1915 } 1916 if (ret) { 1917 /* by definition, a gint64 fits into a gint64; so ignore those */ 1918 if (size != sizeof (mask)) { 1919 if (*to >= 0) { 1920 /* for positive numbers, we create a mask of 1's outside of the range 1921 * and 0's inside the range. An and will thus keep only 1 bits 1922 * outside of the range */ 1923 mask <<= (size * 8); 1924 if ((mask & *to) != 0) { 1925 ret = FALSE; 1926 } 1927 } else { 1928 /* for negative numbers, we do a 2's complement version */ 1929 mask <<= ((size * 8) - 1); 1930 if ((mask & *to) != mask) { 1931 ret = FALSE; 1932 } 1933 } 1934 } 1935 } 1936 return ret; 1937 } 1938 1939 #define CREATE_SERIALIZATION(_type,_macro) \ 1940 CREATE_SERIALIZATION_START(_type,_macro) \ 1941 \ 1942 static gboolean \ 1943 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s) \ 1944 { \ 1945 gint64 x; \ 1946 \ 1947 if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro, \ 1948 G_MAX ## _macro, sizeof (g ## _type))) { \ 1949 g_value_set_ ## _type (dest, /*(g ## _type)*/ x); \ 1950 return TRUE; \ 1951 } else { \ 1952 return FALSE; \ 1953 } \ 1954 } 1955 1956 #define CREATE_USERIALIZATION(_type,_macro) \ 1957 CREATE_SERIALIZATION_START(_type,_macro) \ 1958 \ 1959 static gboolean \ 1960 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s) \ 1961 { \ 1962 gint64 x; \ 1963 gchar *end; \ 1964 gboolean ret = FALSE; \ 1965 \ 1966 errno = 0; \ 1967 x = g_ascii_strtoull (s, &end, 0); \ 1968 /* a range error is a definitive no-no */ \ 1969 if (errno == ERANGE) { \ 1970 return FALSE; \ 1971 } \ 1972 /* the cast ensures the range check later on makes sense */ \ 1973 x = (g ## _type) x; \ 1974 if (*end == 0) { \ 1975 ret = TRUE; \ 1976 } else { \ 1977 if (g_ascii_strcasecmp (s, "little_endian") == 0) { \ 1978 x = G_LITTLE_ENDIAN; \ 1979 ret = TRUE; \ 1980 } else if (g_ascii_strcasecmp (s, "big_endian") == 0) { \ 1981 x = G_BIG_ENDIAN; \ 1982 ret = TRUE; \ 1983 } else if (g_ascii_strcasecmp (s, "byte_order") == 0) { \ 1984 x = G_BYTE_ORDER; \ 1985 ret = TRUE; \ 1986 } else if (g_ascii_strcasecmp (s, "min") == 0) { \ 1987 x = 0; \ 1988 ret = TRUE; \ 1989 } else if (g_ascii_strcasecmp (s, "max") == 0) { \ 1990 x = G_MAX ## _macro; \ 1991 ret = TRUE; \ 1992 } \ 1993 } \ 1994 if (ret) { \ 1995 if (x > G_MAX ## _macro) { \ 1996 ret = FALSE; \ 1997 } else { \ 1998 g_value_set_ ## _type (dest, x); \ 1999 } \ 2000 } \ 2001 return ret; \ 2002 } 2003 2004 #define REGISTER_SERIALIZATION(_gtype, _type) \ 2005 G_STMT_START { \ 2006 static const GstValueTable gst_value = { \ 2007 _gtype, \ 2008 gst_value_compare_ ## _type, \ 2009 gst_value_serialize_ ## _type, \ 2010 gst_value_deserialize_ ## _type, \ 2011 }; \ 2012 \ 2013 gst_value_register (&gst_value); \ 2014 } G_STMT_END 2015 2016 CREATE_SERIALIZATION (int, INT); 2017 CREATE_SERIALIZATION (int64, INT64); 2018 CREATE_SERIALIZATION (long, LONG); 2019 2020 CREATE_USERIALIZATION (uint, UINT); 2021 CREATE_USERIALIZATION (uint64, UINT64); 2022 CREATE_USERIALIZATION (ulong, ULONG); 2023 2024 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */ 2025 #ifndef G_MAXUCHAR 2026 #define G_MAXUCHAR 255 2027 #endif 2028 CREATE_USERIALIZATION (uchar, UCHAR); 2029 2030 /********** 2031 * double * 2032 **********/ 2033 static gint 2034 gst_value_compare_double (const GValue * value1, const GValue * value2) 2035 { 2036 if (value1->data[0].v_double > value2->data[0].v_double) 2037 return GST_VALUE_GREATER_THAN; 2038 if (value1->data[0].v_double < value2->data[0].v_double) 2039 return GST_VALUE_LESS_THAN; 2040 if (value1->data[0].v_double == value2->data[0].v_double) 2041 return GST_VALUE_EQUAL; 2042 return GST_VALUE_UNORDERED; 2043 } 2044 2045 static gchar * 2046 gst_value_serialize_double (const GValue * value) 2047 { 2048 gchar d[G_ASCII_DTOSTR_BUF_SIZE]; 2049 2050 g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double); 2051 return g_strdup (d); 2052 } 2053 2054 static gboolean 2055 gst_value_deserialize_double (GValue * dest, const gchar * s) 2056 { 2057 gdouble x; 2058 gboolean ret = FALSE; 2059 gchar *end; 2060 2061 x = g_ascii_strtod (s, &end); 2062 if (*end == 0) { 2063 ret = TRUE; 2064 } else { 2065 if (g_ascii_strcasecmp (s, "min") == 0) { 2066 x = -G_MAXDOUBLE; 2067 ret = TRUE; 2068 } else if (g_ascii_strcasecmp (s, "max") == 0) { 2069 x = G_MAXDOUBLE; 2070 ret = TRUE; 2071 } 2072 } 2073 if (ret) { 2074 g_value_set_double (dest, x); 2075 } 2076 return ret; 2077 } 2078 2079 /********* 2080 * float * 2081 *********/ 2082 2083 static gint 2084 gst_value_compare_float (const GValue * value1, const GValue * value2) 2085 { 2086 if (value1->data[0].v_float > value2->data[0].v_float) 2087 return GST_VALUE_GREATER_THAN; 2088 if (value1->data[0].v_float < value2->data[0].v_float) 2089 return GST_VALUE_LESS_THAN; 2090 if (value1->data[0].v_float == value2->data[0].v_float) 2091 return GST_VALUE_EQUAL; 2092 return GST_VALUE_UNORDERED; 2093 } 2094 2095 static gchar * 2096 gst_value_serialize_float (const GValue * value) 2097 { 2098 gchar d[G_ASCII_DTOSTR_BUF_SIZE]; 2099 2100 g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float); 2101 return g_strdup (d); 2102 } 2103 2104 static gboolean 2105 gst_value_deserialize_float (GValue * dest, const gchar * s) 2106 { 2107 gdouble x; 2108 gboolean ret = FALSE; 2109 gchar *end; 2110 2111 x = g_ascii_strtod (s, &end); 2112 if (*end == 0) { 2113 ret = TRUE; 2114 } else { 2115 if (g_ascii_strcasecmp (s, "min") == 0) { 2116 x = -G_MAXFLOAT; 2117 ret = TRUE; 2118 } else if (g_ascii_strcasecmp (s, "max") == 0) { 2119 x = G_MAXFLOAT; 2120 ret = TRUE; 2121 } 2122 } 2123 if (x > G_MAXFLOAT || x < -G_MAXFLOAT) 2124 ret = FALSE; 2125 if (ret) { 2126 g_value_set_float (dest, (float) x); 2127 } 2128 return ret; 2129 } 2130 2131 /********** 2132 * string * 2133 **********/ 2134 2135 static gint 2136 gst_value_compare_string (const GValue * value1, const GValue * value2) 2137 { 2138 if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) { 2139 /* if only one is NULL, no match - otherwise both NULL == EQUAL */ 2140 if (value1->data[0].v_pointer != value2->data[0].v_pointer) 2141 return GST_VALUE_UNORDERED; 2142 } else { 2143 gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer); 2144 2145 if (x < 0) 2146 return GST_VALUE_LESS_THAN; 2147 if (x > 0) 2148 return GST_VALUE_GREATER_THAN; 2149 } 2150 2151 return GST_VALUE_EQUAL; 2152 } 2153 2154 static gint 2155 gst_string_measure_wrapping (const gchar * s) 2156 { 2157 gint len; 2158 gboolean wrap = FALSE; 2159 2160 if (G_UNLIKELY (s == NULL)) 2161 return -1; 2162 2163 /* Special case: the actual string NULL needs wrapping */ 2164 if (G_UNLIKELY (strcmp (s, "NULL") == 0)) 2165 return 4; 2166 2167 len = 0; 2168 while (*s) { 2169 if (GST_ASCII_IS_STRING (*s)) { 2170 len++; 2171 } else if (*s < 0x20 || *s >= 0x7f) { 2172 wrap = TRUE; 2173 len += 4; 2174 } else { 2175 wrap = TRUE; 2176 len += 2; 2177 } 2178 s++; 2179 } 2180 2181 /* Wrap the string if we found something that needs 2182 * wrapping, or the empty string (len == 0) */ 2183 return (wrap || len == 0) ? len : -1; 2184 } 2185 2186 static gchar * 2187 gst_string_wrap_inner (const gchar * s, gint len) 2188 { 2189 gchar *d, *e; 2190 2191 e = d = g_malloc (len + 3); 2192 2193 *e++ = '\"'; 2194 while (*s) { 2195 if (GST_ASCII_IS_STRING (*s)) { 2196 *e++ = *s++; 2197 } else if (*s < 0x20 || *s >= 0x7f) { 2198 *e++ = '\\'; 2199 *e++ = '0' + ((*(guchar *) s) >> 6); 2200 *e++ = '0' + (((*s) >> 3) & 0x7); 2201 *e++ = '0' + ((*s++) & 0x7); 2202 } else { 2203 *e++ = '\\'; 2204 *e++ = *s++; 2205 } 2206 } 2207 *e++ = '\"'; 2208 *e = 0; 2209 2210 g_assert (e - d <= len + 3); 2211 return d; 2212 } 2213 2214 /* Do string wrapping/escaping */ 2215 static gchar * 2216 gst_string_wrap (const gchar * s) 2217 { 2218 gint len = gst_string_measure_wrapping (s); 2219 2220 if (G_LIKELY (len < 0)) 2221 return g_strdup (s); 2222 2223 return gst_string_wrap_inner (s, len); 2224 } 2225 2226 /* Same as above, but take ownership of the string */ 2227 static gchar * 2228 gst_string_take_and_wrap (gchar * s) 2229 { 2230 gchar *out; 2231 gint len = gst_string_measure_wrapping (s); 2232 2233 if (G_LIKELY (len < 0)) 2234 return s; 2235 2236 out = gst_string_wrap_inner (s, len); 2237 g_free (s); 2238 2239 return out; 2240 } 2241 2242 /* 2243 * This function takes a string delimited with double quotes (") 2244 * and unescapes any \xxx octal numbers. 2245 * 2246 * If sequences of \y are found where y is not in the range of 2247 * 0->3, y is copied unescaped. 2248 * 2249 * If \xyy is found where x is an octal number but y is not, an 2250 * error is encountered and NULL is returned. 2251 * 2252 * the input string must be \0 terminated. 2253 */ 2254 static gchar * 2255 gst_string_unwrap (const gchar * s) 2256 { 2257 gchar *ret; 2258 gchar *read, *write; 2259 2260 /* NULL string returns NULL */ 2261 if (s == NULL) 2262 return NULL; 2263 2264 /* strings not starting with " are invalid */ 2265 if (*s != '"') 2266 return NULL; 2267 2268 /* make copy of original string to hold the result. This 2269 * string will always be smaller than the original */ 2270 ret = g_strdup (s); 2271 read = ret; 2272 write = ret; 2273 2274 /* need to move to the next position as we parsed the " */ 2275 read++; 2276 2277 while (*read) { 2278 if (GST_ASCII_IS_STRING (*read)) { 2279 /* normal chars are just copied */ 2280 *write++ = *read++; 2281 } else if (*read == '"') { 2282 /* quote marks end of string */ 2283 break; 2284 } else if (*read == '\\') { 2285 /* got an escape char, move to next position to read a tripplet 2286 * of octal numbers */ 2287 read++; 2288 /* is the next char a possible first octal number? */ 2289 if (*read >= '0' && *read <= '3') { 2290 /* parse other 2 numbers, if one of them is not in the range of 2291 * an octal number, we error. We also catch the case where a zero 2292 * byte is found here. */ 2293 if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7') 2294 goto beach; 2295 2296 /* now convert the octal number to a byte again. */ 2297 *write++ = ((read[0] - '0') << 6) + 2298 ((read[1] - '0') << 3) + (read[2] - '0'); 2299 2300 read += 3; 2301 } else { 2302 /* if we run into a \0 here, we definately won't get a quote later */ 2303 if (*read == 0) 2304 goto beach; 2305 2306 /* else copy \X sequence */ 2307 *write++ = *read++; 2308 } 2309 } else { 2310 /* weird character, error */ 2311 goto beach; 2312 } 2313 } 2314 /* if the string is not ending in " and zero terminated, we error */ 2315 if (*read != '"' || read[1] != '\0') 2316 goto beach; 2317 2318 /* null terminate result string and return */ 2319 *write = '\0'; 2320 return ret; 2321 2322 beach: 2323 g_free (ret); 2324 return NULL; 2325 } 2326 2327 static gchar * 2328 gst_value_serialize_string (const GValue * value) 2329 { 2330 return gst_string_wrap (value->data[0].v_pointer); 2331 } 2332 2333 static gboolean 2334 gst_value_deserialize_string (GValue * dest, const gchar * s) 2335 { 2336 if (G_UNLIKELY (strcmp (s, "NULL") == 0)) { 2337 g_value_set_string (dest, NULL); 2338 return TRUE; 2339 } else if (G_LIKELY (*s != '"')) { 2340 if (!g_utf8_validate (s, -1, NULL)) 2341 return FALSE; 2342 g_value_set_string (dest, s); 2343 return TRUE; 2344 } else { 2345 gchar *str = gst_string_unwrap (s); 2346 if (G_UNLIKELY (!str)) 2347 return FALSE; 2348 g_value_take_string (dest, str); 2349 } 2350 2351 return TRUE; 2352 } 2353 2354 /******** 2355 * enum * 2356 ********/ 2357 2358 static gint 2359 gst_value_compare_enum (const GValue * value1, const GValue * value2) 2360 { 2361 GEnumValue *en1, *en2; 2362 GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1)); 2363 GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2)); 2364 2365 g_return_val_if_fail (klass1, GST_VALUE_UNORDERED); 2366 g_return_val_if_fail (klass2, GST_VALUE_UNORDERED); 2367 en1 = g_enum_get_value (klass1, g_value_get_enum (value1)); 2368 en2 = g_enum_get_value (klass2, g_value_get_enum (value2)); 2369 g_type_class_unref (klass1); 2370 g_type_class_unref (klass2); 2371 g_return_val_if_fail (en1, GST_VALUE_UNORDERED); 2372 g_return_val_if_fail (en2, GST_VALUE_UNORDERED); 2373 if (en1->value < en2->value) 2374 return GST_VALUE_LESS_THAN; 2375 if (en1->value > en2->value) 2376 return GST_VALUE_GREATER_THAN; 2377 2378 return GST_VALUE_EQUAL; 2379 } 2380 2381 static gchar * 2382 gst_value_serialize_enum (const GValue * value) 2383 { 2384 GEnumValue *en; 2385 GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value)); 2386 2387 g_return_val_if_fail (klass, NULL); 2388 en = g_enum_get_value (klass, g_value_get_enum (value)); 2389 g_type_class_unref (klass); 2390 2391 /* might be one of the custom formats registered later */ 2392 if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) { 2393 const GstFormatDefinition *format_def; 2394 2395 format_def = gst_format_get_details (g_value_get_enum (value)); 2396 g_return_val_if_fail (format_def != NULL, NULL); 2397 return g_strdup (format_def->description); 2398 } 2399 2400 g_return_val_if_fail (en, NULL); 2401 return g_strdup (en->value_name); 2402 } 2403 2404 static gint 2405 gst_value_deserialize_enum_iter_cmp (const GstFormatDefinition * format_def, 2406 const gchar * s) 2407 { 2408 if (g_ascii_strcasecmp (s, format_def->nick) == 0) 2409 return 0; 2410 2411 return g_ascii_strcasecmp (s, format_def->description); 2412 } 2413 2414 static gboolean 2415 gst_value_deserialize_enum (GValue * dest, const gchar * s) 2416 { 2417 GEnumValue *en; 2418 gchar *endptr = NULL; 2419 GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest)); 2420 2421 g_return_val_if_fail (klass, FALSE); 2422 if (!(en = g_enum_get_value_by_name (klass, s))) { 2423 if (!(en = g_enum_get_value_by_nick (klass, s))) { 2424 gint i = strtol (s, &endptr, 0); 2425 2426 if (endptr && *endptr == '\0') { 2427 en = g_enum_get_value (klass, i); 2428 } 2429 } 2430 } 2431 g_type_class_unref (klass); 2432 2433 /* might be one of the custom formats registered later */ 2434 if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) { 2435 const GstFormatDefinition *format_def; 2436 GstIterator *iter; 2437 2438 iter = gst_format_iterate_definitions (); 2439 2440 format_def = gst_iterator_find_custom (iter, 2441 (GCompareFunc) gst_value_deserialize_enum_iter_cmp, (gpointer) s); 2442 2443 g_return_val_if_fail (format_def != NULL, FALSE); 2444 g_value_set_enum (dest, (gint) format_def->value); 2445 gst_iterator_free (iter); 2446 return TRUE; 2447 } 2448 2449 g_return_val_if_fail (en, FALSE); 2450 g_value_set_enum (dest, en->value); 2451 return TRUE; 2452 } 2453 2454 /******** 2455 * flags * 2456 ********/ 2457 2458 /* we just compare the value here */ 2459 static gint 2460 gst_value_compare_flags (const GValue * value1, const GValue * value2) 2461 { 2462 guint fl1, fl2; 2463 GFlagsClass *klass1 = 2464 (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1)); 2465 GFlagsClass *klass2 = 2466 (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2)); 2467 2468 g_return_val_if_fail (klass1, GST_VALUE_UNORDERED); 2469 g_return_val_if_fail (klass2, GST_VALUE_UNORDERED); 2470 fl1 = g_value_get_flags (value1); 2471 fl2 = g_value_get_flags (value2); 2472 g_type_class_unref (klass1); 2473 g_type_class_unref (klass2); 2474 if (fl1 < fl2) 2475 return GST_VALUE_LESS_THAN; 2476 if (fl1 > fl2) 2477 return GST_VALUE_GREATER_THAN; 2478 2479 return GST_VALUE_EQUAL; 2480 } 2481 2482 /* the different flags are serialized separated with a + */ 2483 static gchar * 2484 gst_value_serialize_flags (const GValue * value) 2485 { 2486 guint flags; 2487 GFlagsValue *fl; 2488 GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value)); 2489 gchar *result, *tmp; 2490 gboolean first = TRUE; 2491 2492 g_return_val_if_fail (klass, NULL); 2493 2494 flags = g_value_get_flags (value); 2495 2496 /* if no flags are set, try to serialize to the _NONE string */ 2497 if (!flags) { 2498 fl = g_flags_get_first_value (klass, flags); 2499 return g_strdup (fl->value_name); 2500 } 2501 2502 /* some flags are set, so serialize one by one */ 2503 result = g_strdup (""); 2504 while (flags) { 2505 fl = g_flags_get_first_value (klass, flags); 2506 if (fl != NULL) { 2507 tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL); 2508 g_free (result); 2509 result = tmp; 2510 first = FALSE; 2511 2512 /* clear flag */ 2513 flags &= ~fl->value; 2514 } 2515 } 2516 g_type_class_unref (klass); 2517 2518 return result; 2519 } 2520 2521 static gboolean 2522 gst_value_deserialize_flags (GValue * dest, const gchar * s) 2523 { 2524 GFlagsValue *fl; 2525 gchar *endptr = NULL; 2526 GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest)); 2527 gchar **split; 2528 guint flags; 2529 gint i; 2530 2531 g_return_val_if_fail (klass, FALSE); 2532 2533 /* split into parts delimited with + */ 2534 split = g_strsplit (s, "+", 0); 2535 2536 flags = 0; 2537 i = 0; 2538 /* loop over each part */ 2539 while (split[i]) { 2540 if (!(fl = g_flags_get_value_by_name (klass, split[i]))) { 2541 if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) { 2542 gint val = strtol (split[i], &endptr, 0); 2543 2544 /* just or numeric value */ 2545 if (endptr && *endptr == '\0') { 2546 flags |= val; 2547 } 2548 } 2549 } 2550 if (fl) { 2551 flags |= fl->value; 2552 } 2553 i++; 2554 } 2555 g_strfreev (split); 2556 g_type_class_unref (klass); 2557 g_value_set_flags (dest, flags); 2558 2559 return TRUE; 2560 } 2561 2562 /********* 2563 * union * 2564 *********/ 2565 2566 static gboolean 2567 gst_value_union_int_int_range (GValue * dest, const GValue * src1, 2568 const GValue * src2) 2569 { 2570 if (src2->data[0].v_int <= src1->data[0].v_int && 2571 src2->data[1].v_int >= src1->data[0].v_int) { 2572 gst_value_init_and_copy (dest, src2); 2573 return TRUE; 2574 } 2575 return FALSE; 2576 } 2577 2578 static gboolean 2579 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1, 2580 const GValue * src2) 2581 { 2582 gint min; 2583 gint max; 2584 2585 min = MAX (src1->data[0].v_int, src2->data[0].v_int); 2586 max = MIN (src1->data[1].v_int, src2->data[1].v_int); 2587 2588 if (min <= max) { 2589 g_value_init (dest, GST_TYPE_INT_RANGE); 2590 gst_value_set_int_range (dest, 2591 MIN (src1->data[0].v_int, src2->data[0].v_int), 2592 MAX (src1->data[1].v_int, src2->data[1].v_int)); 2593 return TRUE; 2594 } 2595 2596 return FALSE; 2597 } 2598 2599 /**************** 2600 * intersection * 2601 ****************/ 2602 2603 static gboolean 2604 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1, 2605 const GValue * src2) 2606 { 2607 if (src2->data[0].v_int <= src1->data[0].v_int && 2608 src2->data[1].v_int >= src1->data[0].v_int) { 2609 gst_value_init_and_copy (dest, src1); 2610 return TRUE; 2611 } 2612 2613 return FALSE; 2614 } 2615 2616 static gboolean 2617 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1, 2618 const GValue * src2) 2619 { 2620 gint min; 2621 gint max; 2622 2623 min = MAX (src1->data[0].v_int, src2->data[0].v_int); 2624 max = MIN (src1->data[1].v_int, src2->data[1].v_int); 2625 2626 if (min < max) { 2627 g_value_init (dest, GST_TYPE_INT_RANGE); 2628 gst_value_set_int_range (dest, min, max); 2629 return TRUE; 2630 } 2631 if (min == max) { 2632 g_value_init (dest, G_TYPE_INT); 2633 g_value_set_int (dest, min); 2634 return TRUE; 2635 } 2636 2637 return FALSE; 2638 } 2639 2640 static gboolean 2641 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1, 2642 const GValue * src2) 2643 { 2644 if (src2->data[0].v_int64 <= src1->data[0].v_int64 && 2645 src2->data[1].v_int64 >= src1->data[0].v_int64) { 2646 gst_value_init_and_copy (dest, src1); 2647 return TRUE; 2648 } 2649 2650 return FALSE; 2651 } 2652 2653 static gboolean 2654 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1, 2655 const GValue * src2) 2656 { 2657 gint64 min; 2658 gint64 max; 2659 2660 min = MAX (src1->data[0].v_int64, src2->data[0].v_int64); 2661 max = MIN (src1->data[1].v_int64, src2->data[1].v_int64); 2662 2663 if (min < max) { 2664 g_value_init (dest, GST_TYPE_INT64_RANGE); 2665 gst_value_set_int64_range (dest, min, max); 2666 return TRUE; 2667 } 2668 if (min == max) { 2669 g_value_init (dest, G_TYPE_INT64); 2670 g_value_set_int64 (dest, min); 2671 return TRUE; 2672 } 2673 2674 return FALSE; 2675 } 2676 2677 static gboolean 2678 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1, 2679 const GValue * src2) 2680 { 2681 if (src2->data[0].v_double <= src1->data[0].v_double && 2682 src2->data[1].v_double >= src1->data[0].v_double) { 2683 gst_value_init_and_copy (dest, src1); 2684 return TRUE; 2685 } 2686 2687 return FALSE; 2688 } 2689 2690 static gboolean 2691 gst_value_intersect_double_range_double_range (GValue * dest, 2692 const GValue * src1, const GValue * src2) 2693 { 2694 gdouble min; 2695 gdouble max; 2696 2697 min = MAX (src1->data[0].v_double, src2->data[0].v_double); 2698 max = MIN (src1->data[1].v_double, src2->data[1].v_double); 2699 2700 if (min < max) { 2701 g_value_init (dest, GST_TYPE_DOUBLE_RANGE); 2702 gst_value_set_double_range (dest, min, max); 2703 return TRUE; 2704 } 2705 if (min == max) { 2706 g_value_init (dest, G_TYPE_DOUBLE); 2707 g_value_set_int (dest, (int) min); 2708 return TRUE; 2709 } 2710 2711 return FALSE; 2712 } 2713 2714 static gboolean 2715 gst_value_intersect_list (GValue * dest, const GValue * value1, 2716 const GValue * value2) 2717 { 2718 guint i, size; 2719 GValue intersection = { 0, }; 2720 gboolean ret = FALSE; 2721 2722 size = VALUE_LIST_SIZE (value1); 2723 for (i = 0; i < size; i++) { 2724 const GValue *cur = VALUE_LIST_GET_VALUE (value1, i); 2725 2726 if (gst_value_intersect (&intersection, cur, value2)) { 2727 /* append value */ 2728 if (!ret) { 2729 gst_value_init_and_copy (dest, &intersection); 2730 ret = TRUE; 2731 } else if (GST_VALUE_HOLDS_LIST (dest)) { 2732 gst_value_list_append_value (dest, &intersection); 2733 } else { 2734 GValue temp = { 0, }; 2735 2736 gst_value_init_and_copy (&temp, dest); 2737 g_value_unset (dest); 2738 gst_value_list_concat (dest, &temp, &intersection); 2739 g_value_unset (&temp); 2740 } 2741 g_value_unset (&intersection); 2742 } 2743 } 2744 2745 return ret; 2746 } 2747 2748 static gboolean 2749 gst_value_intersect_array (GValue * dest, const GValue * src1, 2750 const GValue * src2) 2751 { 2752 guint size; 2753 guint n; 2754 GValue val = { 0 }; 2755 2756 /* only works on similar-sized arrays */ 2757 size = gst_value_array_get_size (src1); 2758 if (size != gst_value_array_get_size (src2)) 2759 return FALSE; 2760 g_value_init (dest, GST_TYPE_ARRAY); 2761 2762 for (n = 0; n < size; n++) { 2763 if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n), 2764 gst_value_array_get_value (src2, n))) { 2765 g_value_unset (dest); 2766 return FALSE; 2767 } 2768 gst_value_array_append_value (dest, &val); 2769 g_value_unset (&val); 2770 } 2771 2772 return TRUE; 2773 } 2774 2775 static gboolean 2776 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1, 2777 const GValue * src2) 2778 { 2779 gint res1, res2; 2780 GValue *vals; 2781 GstValueCompareFunc compare; 2782 2783 vals = src2->data[0].v_pointer; 2784 2785 if (vals == NULL) 2786 return FALSE; 2787 2788 if ((compare = gst_value_get_compare_func (src1))) { 2789 res1 = gst_value_compare_with_func (&vals[0], src1, compare); 2790 res2 = gst_value_compare_with_func (&vals[1], src1, compare); 2791 2792 if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) && 2793 (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) { 2794 gst_value_init_and_copy (dest, src1); 2795 return TRUE; 2796 } 2797 } 2798 2799 return FALSE; 2800 } 2801 2802 static gboolean 2803 gst_value_intersect_fraction_range_fraction_range (GValue * dest, 2804 const GValue * src1, const GValue * src2) 2805 { 2806 GValue *min; 2807 GValue *max; 2808 gint res; 2809 GValue *vals1, *vals2; 2810 GstValueCompareFunc compare; 2811 2812 vals1 = src1->data[0].v_pointer; 2813 vals2 = src2->data[0].v_pointer; 2814 g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE); 2815 2816 if ((compare = gst_value_get_compare_func (&vals1[0]))) { 2817 /* min = MAX (src1.start, src2.start) */ 2818 res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare); 2819 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); 2820 if (res == GST_VALUE_LESS_THAN) 2821 min = &vals2[0]; /* Take the max of the 2 */ 2822 else 2823 min = &vals1[0]; 2824 2825 /* max = MIN (src1.end, src2.end) */ 2826 res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare); 2827 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); 2828 if (res == GST_VALUE_GREATER_THAN) 2829 max = &vals2[1]; /* Take the min of the 2 */ 2830 else 2831 max = &vals1[1]; 2832 2833 res = gst_value_compare_with_func (min, max, compare); 2834 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE); 2835 if (res == GST_VALUE_LESS_THAN) { 2836 g_value_init (dest, GST_TYPE_FRACTION_RANGE); 2837 vals1 = dest->data[0].v_pointer; 2838 g_value_copy (min, &vals1[0]); 2839 g_value_copy (max, &vals1[1]); 2840 return TRUE; 2841 } 2842 if (res == GST_VALUE_EQUAL) { 2843 gst_value_init_and_copy (dest, min); 2844 return TRUE; 2845 } 2846 } 2847 2848 return FALSE; 2849 } 2850 2851 /*************** 2852 * subtraction * 2853 ***************/ 2854 2855 static gboolean 2856 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend, 2857 const GValue * subtrahend) 2858 { 2859 gint min = gst_value_get_int_range_min (subtrahend); 2860 gint max = gst_value_get_int_range_max (subtrahend); 2861 gint val = g_value_get_int (minuend); 2862 2863 /* subtracting a range from an int only works if the int is not in the 2864 * range */ 2865 if (val < min || val > max) { 2866 /* and the result is the int */ 2867 gst_value_init_and_copy (dest, minuend); 2868 return TRUE; 2869 } 2870 return FALSE; 2871 } 2872 2873 /* creates a new int range based on input values. 2874 */ 2875 static gboolean 2876 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2, 2877 gint max2) 2878 { 2879 GValue v1 = { 0, }; 2880 GValue v2 = { 0, }; 2881 GValue *pv1, *pv2; /* yeah, hungarian! */ 2882 2883 if (min1 <= max1 && min2 <= max2) { 2884 pv1 = &v1; 2885 pv2 = &v2; 2886 } else if (min1 <= max1) { 2887 pv1 = dest; 2888 pv2 = NULL; 2889 } else if (min2 <= max2) { 2890 pv1 = NULL; 2891 pv2 = dest; 2892 } else { 2893 return FALSE; 2894 } 2895 2896 if (min1 < max1) { 2897 g_value_init (pv1, GST_TYPE_INT_RANGE); 2898 gst_value_set_int_range (pv1, min1, max1); 2899 } else if (min1 == max1) { 2900 g_value_init (pv1, G_TYPE_INT); 2901 g_value_set_int (pv1, min1); 2902 } 2903 if (min2 < max2) { 2904 g_value_init (pv2, GST_TYPE_INT_RANGE); 2905 gst_value_set_int_range (pv2, min2, max2); 2906 } else if (min2 == max2) { 2907 g_value_init (pv2, G_TYPE_INT); 2908 g_value_set_int (pv2, min2); 2909 } 2910 2911 if (min1 <= max1 && min2 <= max2) { 2912 gst_value_list_concat (dest, pv1, pv2); 2913 g_value_unset (pv1); 2914 g_value_unset (pv2); 2915 } 2916 return TRUE; 2917 } 2918 2919 static gboolean 2920 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend, 2921 const GValue * subtrahend) 2922 { 2923 gint min = gst_value_get_int_range_min (minuend); 2924 gint max = gst_value_get_int_range_max (minuend); 2925 gint val = g_value_get_int (subtrahend); 2926 2927 g_return_val_if_fail (min < max, FALSE); 2928 2929 /* value is outside of the range, return range unchanged */ 2930 if (val < min || val > max) { 2931 gst_value_init_and_copy (dest, minuend); 2932 return TRUE; 2933 } else { 2934 /* max must be MAXINT too as val <= max */ 2935 if (val == G_MAXINT) { 2936 max--; 2937 val--; 2938 } 2939 /* min must be MININT too as val >= max */ 2940 if (val == G_MININT) { 2941 min++; 2942 val++; 2943 } 2944 gst_value_create_new_range (dest, min, val - 1, val + 1, max); 2945 } 2946 return TRUE; 2947 } 2948 2949 static gboolean 2950 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend, 2951 const GValue * subtrahend) 2952 { 2953 gint min1 = gst_value_get_int_range_min (minuend); 2954 gint max1 = gst_value_get_int_range_max (minuend); 2955 gint min2 = gst_value_get_int_range_min (subtrahend); 2956 gint max2 = gst_value_get_int_range_max (subtrahend); 2957 2958 if (max2 == G_MAXINT && min2 == G_MININT) { 2959 return FALSE; 2960 } else if (max2 == G_MAXINT) { 2961 return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0); 2962 } else if (min2 == G_MININT) { 2963 return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0); 2964 } else { 2965 return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 2966 MAX (max2 + 1, min1), max1); 2967 } 2968 } 2969 2970 static gboolean 2971 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend, 2972 const GValue * subtrahend) 2973 { 2974 gint64 min = gst_value_get_int64_range_min (subtrahend); 2975 gint64 max = gst_value_get_int64_range_max (subtrahend); 2976 gint64 val = g_value_get_int64 (minuend); 2977 2978 /* subtracting a range from an int64 only works if the int64 is not in the 2979 * range */ 2980 if (val < min || val > max) { 2981 /* and the result is the int64 */ 2982 gst_value_init_and_copy (dest, minuend); 2983 return TRUE; 2984 } 2985 return FALSE; 2986 } 2987 2988 /* creates a new int64 range based on input values. 2989 */ 2990 static gboolean 2991 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1, 2992 gint64 min2, gint64 max2) 2993 { 2994 GValue v1 = { 0, }; 2995 GValue v2 = { 0, }; 2996 GValue *pv1, *pv2; /* yeah, hungarian! */ 2997 2998 if (min1 <= max1 && min2 <= max2) { 2999 pv1 = &v1; 3000 pv2 = &v2; 3001 } else if (min1 <= max1) { 3002 pv1 = dest; 3003 pv2 = NULL; 3004 } else if (min2 <= max2) { 3005 pv1 = NULL; 3006 pv2 = dest; 3007 } else { 3008 return FALSE; 3009 } 3010 3011 if (min1 < max1) { 3012 g_value_init (pv1, GST_TYPE_INT64_RANGE); 3013 gst_value_set_int64_range (pv1, min1, max1); 3014 } else if (min1 == max1) { 3015 g_value_init (pv1, G_TYPE_INT64); 3016 g_value_set_int64 (pv1, min1); 3017 } 3018 if (min2 < max2) { 3019 g_value_init (pv2, GST_TYPE_INT64_RANGE); 3020 gst_value_set_int64_range (pv2, min2, max2); 3021 } else if (min2 == max2) { 3022 g_value_init (pv2, G_TYPE_INT64); 3023 g_value_set_int64 (pv2, min2); 3024 } 3025 3026 if (min1 <= max1 && min2 <= max2) { 3027 gst_value_list_concat (dest, pv1, pv2); 3028 g_value_unset (pv1); 3029 g_value_unset (pv2); 3030 } 3031 return TRUE; 3032 } 3033 3034 static gboolean 3035 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend, 3036 const GValue * subtrahend) 3037 { 3038 gint64 min = gst_value_get_int64_range_min (minuend); 3039 gint64 max = gst_value_get_int64_range_max (minuend); 3040 gint64 val = g_value_get_int64 (subtrahend); 3041 3042 g_return_val_if_fail (min < max, FALSE); 3043 3044 /* value is outside of the range, return range unchanged */ 3045 if (val < min || val > max) { 3046 gst_value_init_and_copy (dest, minuend); 3047 return TRUE; 3048 } else { 3049 /* max must be MAXINT64 too as val <= max */ 3050 if (val == G_MAXINT64) { 3051 max--; 3052 val--; 3053 } 3054 /* min must be MININT64 too as val >= max */ 3055 if (val == G_MININT64) { 3056 min++; 3057 val++; 3058 } 3059 gst_value_create_new_int64_range (dest, min, val - 1, val + 1, max); 3060 } 3061 return TRUE; 3062 } 3063 3064 static gboolean 3065 gst_value_subtract_int64_range_int64_range (GValue * dest, 3066 const GValue * minuend, const GValue * subtrahend) 3067 { 3068 gint64 min1 = gst_value_get_int64_range_min (minuend); 3069 gint64 max1 = gst_value_get_int64_range_max (minuend); 3070 gint64 min2 = gst_value_get_int64_range_min (subtrahend); 3071 gint64 max2 = gst_value_get_int64_range_max (subtrahend); 3072 3073 if (max2 == G_MAXINT64 && min2 == G_MININT64) { 3074 return FALSE; 3075 } else if (max2 == G_MAXINT64) { 3076 return gst_value_create_new_int64_range (dest, min1, MIN (min2 - 1, max1), 3077 1, 0); 3078 } else if (min2 == G_MININT64) { 3079 return gst_value_create_new_int64_range (dest, MAX (max2 + 1, min1), max1, 3080 1, 0); 3081 } else { 3082 return gst_value_create_new_int64_range (dest, min1, MIN (min2 - 1, max1), 3083 MAX (max2 + 1, min1), max1); 3084 } 3085 } 3086 3087 static gboolean 3088 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend, 3089 const GValue * subtrahend) 3090 { 3091 gdouble min = gst_value_get_double_range_min (subtrahend); 3092 gdouble max = gst_value_get_double_range_max (subtrahend); 3093 gdouble val = g_value_get_double (minuend); 3094 3095 if (val < min || val > max) { 3096 gst_value_init_and_copy (dest, minuend); 3097 return TRUE; 3098 } 3099 return FALSE; 3100 } 3101 3102 static gboolean 3103 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend, 3104 const GValue * subtrahend) 3105 { 3106 /* since we don't have open ranges, we cannot create a hole in 3107 * a double range. We return the original range */ 3108 gst_value_init_and_copy (dest, minuend); 3109 return TRUE; 3110 } 3111 3112 static gboolean 3113 gst_value_subtract_double_range_double_range (GValue * dest, 3114 const GValue * minuend, const GValue * subtrahend) 3115 { 3116 /* since we don't have open ranges, we have to approximate */ 3117 /* done like with ints */ 3118 gdouble min1 = gst_value_get_double_range_min (minuend); 3119 gdouble max2 = gst_value_get_double_range_max (minuend); 3120 gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2); 3121 gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1); 3122 GValue v1 = { 0, }; 3123 GValue v2 = { 0, }; 3124 GValue *pv1, *pv2; /* yeah, hungarian! */ 3125 3126 if (min1 < max1 && min2 < max2) { 3127 pv1 = &v1; 3128 pv2 = &v2; 3129 } else if (min1 < max1) { 3130 pv1 = dest; 3131 pv2 = NULL; 3132 } else if (min2 < max2) { 3133 pv1 = NULL; 3134 pv2 = dest; 3135 } else { 3136 return FALSE; 3137 } 3138 3139 if (min1 < max1) { 3140 g_value_init (pv1, GST_TYPE_DOUBLE_RANGE); 3141 gst_value_set_double_range (pv1, min1, max1); 3142 } 3143 if (min2 < max2) { 3144 g_value_init (pv2, GST_TYPE_DOUBLE_RANGE); 3145 gst_value_set_double_range (pv2, min2, max2); 3146 } 3147 3148 if (min1 < max1 && min2 < max2) { 3149 gst_value_list_concat (dest, pv1, pv2); 3150 g_value_unset (pv1); 3151 g_value_unset (pv2); 3152 } 3153 return TRUE; 3154 } 3155 3156 static gboolean 3157 gst_value_subtract_from_list (GValue * dest, const GValue * minuend, 3158 const GValue * subtrahend) 3159 { 3160 guint i, size; 3161 GValue subtraction = { 0, }; 3162 gboolean ret = FALSE; 3163 GType ltype; 3164 3165 ltype = gst_value_list_get_type (); 3166 3167 size = VALUE_LIST_SIZE (minuend); 3168 for (i = 0; i < size; i++) { 3169 const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i); 3170 3171 if (gst_value_subtract (&subtraction, cur, subtrahend)) { 3172 if (!ret) { 3173 gst_value_init_and_copy (dest, &subtraction); 3174 ret = TRUE; 3175 } else if (G_VALUE_HOLDS (dest, ltype) 3176 && !G_VALUE_HOLDS (&subtraction, ltype)) { 3177 gst_value_list_append_value (dest, &subtraction); 3178 } else { 3179 GValue temp = { 0, }; 3180 3181 gst_value_init_and_copy (&temp, dest); 3182 g_value_unset (dest); 3183 gst_value_list_concat (dest, &temp, &subtraction); 3184 g_value_unset (&temp); 3185 } 3186 g_value_unset (&subtraction); 3187 } 3188 } 3189 return ret; 3190 } 3191 3192 static gboolean 3193 gst_value_subtract_list (GValue * dest, const GValue * minuend, 3194 const GValue * subtrahend) 3195 { 3196 guint i, size; 3197 GValue data[2] = { {0,}, {0,} }; 3198 GValue *subtraction = &data[0], *result = &data[1]; 3199 3200 gst_value_init_and_copy (result, minuend); 3201 size = VALUE_LIST_SIZE (subtrahend); 3202 for (i = 0; i < size; i++) { 3203 const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i); 3204 3205 if (gst_value_subtract (subtraction, result, cur)) { 3206 GValue *temp = result; 3207 3208 result = subtraction; 3209 subtraction = temp; 3210 g_value_unset (subtraction); 3211 } else { 3212 g_value_unset (result); 3213 return FALSE; 3214 } 3215 } 3216 gst_value_init_and_copy (dest, result); 3217 g_value_unset (result); 3218 return TRUE; 3219 } 3220 3221 static gboolean 3222 gst_value_subtract_fraction_fraction_range (GValue * dest, 3223 const GValue * minuend, const GValue * subtrahend) 3224 { 3225 const GValue *min = gst_value_get_fraction_range_min (subtrahend); 3226 const GValue *max = gst_value_get_fraction_range_max (subtrahend); 3227 GstValueCompareFunc compare; 3228 3229 if ((compare = gst_value_get_compare_func (minuend))) { 3230 /* subtracting a range from an fraction only works if the fraction 3231 * is not in the range */ 3232 if (gst_value_compare_with_func (minuend, min, compare) == 3233 GST_VALUE_LESS_THAN || 3234 gst_value_compare_with_func (minuend, max, compare) == 3235 GST_VALUE_GREATER_THAN) { 3236 /* and the result is the value */ 3237 gst_value_init_and_copy (dest, minuend); 3238 return TRUE; 3239 } 3240 } 3241 return FALSE; 3242 } 3243 3244 static gboolean 3245 gst_value_subtract_fraction_range_fraction (GValue * dest, 3246 const GValue * minuend, const GValue * subtrahend) 3247 { 3248 /* since we don't have open ranges, we cannot create a hole in 3249 * a range. We return the original range */ 3250 gst_value_init_and_copy (dest, minuend); 3251 return TRUE; 3252 } 3253 3254 static gboolean 3255 gst_value_subtract_fraction_range_fraction_range (GValue * dest, 3256 const GValue * minuend, const GValue * subtrahend) 3257 { 3258 /* since we don't have open ranges, we have to approximate */ 3259 /* done like with ints and doubles. Creates a list of 2 fraction ranges */ 3260 const GValue *min1 = gst_value_get_fraction_range_min (minuend); 3261 const GValue *max2 = gst_value_get_fraction_range_max (minuend); 3262 const GValue *max1 = gst_value_get_fraction_range_min (subtrahend); 3263 const GValue *min2 = gst_value_get_fraction_range_max (subtrahend); 3264 gint cmp1, cmp2; 3265 GValue v1 = { 0, }; 3266 GValue v2 = { 0, }; 3267 GValue *pv1, *pv2; /* yeah, hungarian! */ 3268 GstValueCompareFunc compare; 3269 3270 g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE); 3271 g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE); 3272 #ifdef GSTREAMER_LITE 3273 if (min1 == NULL || max1 == NULL || min2 == NULL || max2 == NULL) 3274 return FALSE; 3275 #endif // GSTREAMER_LITE 3276 3277 compare = gst_value_get_compare_func (min1); 3278 g_return_val_if_fail (compare, FALSE); 3279 3280 cmp1 = gst_value_compare_with_func (max2, max1, compare); 3281 g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE); 3282 if (cmp1 == GST_VALUE_LESS_THAN) 3283 max1 = max2; 3284 cmp1 = gst_value_compare_with_func (min1, min2, compare); 3285 g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE); 3286 if (cmp1 == GST_VALUE_GREATER_THAN) 3287 min2 = min1; 3288 3289 cmp1 = gst_value_compare_with_func (min1, max1, compare); 3290 cmp2 = gst_value_compare_with_func (min2, max2, compare); 3291 3292 if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) { 3293 pv1 = &v1; 3294 pv2 = &v2; 3295 } else if (cmp1 == GST_VALUE_LESS_THAN) { 3296 pv1 = dest; 3297 pv2 = NULL; 3298 } else if (cmp2 == GST_VALUE_LESS_THAN) { 3299 pv1 = NULL; 3300 pv2 = dest; 3301 } else { 3302 return FALSE; 3303 } 3304 3305 if (cmp1 == GST_VALUE_LESS_THAN) { 3306 g_value_init (pv1, GST_TYPE_FRACTION_RANGE); 3307 gst_value_set_fraction_range (pv1, min1, max1); 3308 } 3309 if (cmp2 == GST_VALUE_LESS_THAN) { 3310 g_value_init (pv2, GST_TYPE_FRACTION_RANGE); 3311 gst_value_set_fraction_range (pv2, min2, max2); 3312 } 3313 3314 if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) { 3315 gst_value_list_concat (dest, pv1, pv2); 3316 g_value_unset (pv1); 3317 g_value_unset (pv2); 3318 } 3319 return TRUE; 3320 } 3321 3322 3323 /************** 3324 * comparison * 3325 **************/ 3326 3327 /* 3328 * gst_value_get_compare_func: 3329 * @value1: a value to get the compare function for 3330 * 3331 * Determines the compare function to be used with values of the same type as 3332 * @value1. The function can be given to gst_value_compare_with_func(). 3333 * 3334 * Returns: A #GstValueCompareFunc value 3335 */ 3336 static GstValueCompareFunc 3337 gst_value_get_compare_func (const GValue * value1) 3338 { 3339 GstValueTable *table, *best = NULL; 3340 guint i; 3341 GType type1; 3342 3343 type1 = G_VALUE_TYPE (value1); 3344 3345 /* this is a fast check */ 3346 best = gst_value_hash_lookup_type (type1); 3347 3348 /* slower checks */ 3349 if (G_UNLIKELY (!best || !best->compare)) { 3350 guint len = gst_value_table->len; 3351 3352 best = NULL; 3353 for (i = 0; i < len; i++) { 3354 table = &g_array_index (gst_value_table, GstValueTable, i); 3355 if (table->compare && g_type_is_a (type1, table->type)) { 3356 if (!best || g_type_is_a (table->type, best->type)) 3357 best = table; 3358 } 3359 } 3360 } 3361 if (G_LIKELY (best)) 3362 return best->compare; 3363 3364 return NULL; 3365 } 3366 3367 /** 3368 * gst_value_can_compare: 3369 * @value1: a value to compare 3370 * @value2: another value to compare 3371 * 3372 * Determines if @value1 and @value2 can be compared. 3373 * 3374 * Returns: TRUE if the values can be compared 3375 */ 3376 gboolean 3377 gst_value_can_compare (const GValue * value1, const GValue * value2) 3378 { 3379 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 3380 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 3381 3382 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) 3383 return FALSE; 3384 3385 return gst_value_get_compare_func (value1) != NULL; 3386 } 3387 3388 /** 3389 * gst_value_compare: 3390 * @value1: a value to compare 3391 * @value2: another value to compare 3392 * 3393 * Compares @value1 and @value2. If @value1 and @value2 cannot be 3394 * compared, the function returns GST_VALUE_UNORDERED. Otherwise, 3395 * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned. 3396 * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned. 3397 * If the values are equal, GST_VALUE_EQUAL is returned. 3398 * 3399 * Returns: comparison result 3400 */ 3401 gint 3402 gst_value_compare (const GValue * value1, const GValue * value2) 3403 { 3404 GstValueCompareFunc compare; 3405 3406 g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN); 3407 g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN); 3408 3409 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) 3410 return GST_VALUE_UNORDERED; 3411 3412 compare = gst_value_get_compare_func (value1); 3413 if (compare) { 3414 return compare (value1, value2); 3415 } 3416 3417 g_critical ("unable to compare values of type %s\n", 3418 g_type_name (G_VALUE_TYPE (value1))); 3419 return GST_VALUE_UNORDERED; 3420 } 3421 3422 /* 3423 * gst_value_compare_with_func: 3424 * @value1: a value to compare 3425 * @value2: another value to compare 3426 * @compare: compare function 3427 * 3428 * Compares @value1 and @value2 using the @compare function. Works like 3429 * gst_value_compare() but allows to save time determining the compare function 3430 * a multiple times. 3431 * 3432 * Returns: comparison result 3433 */ 3434 static gint 3435 gst_value_compare_with_func (const GValue * value1, const GValue * value2, 3436 GstValueCompareFunc compare) 3437 { 3438 g_assert (compare); 3439 3440 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2)) 3441 return GST_VALUE_UNORDERED; 3442 3443 return compare (value1, value2); 3444 } 3445 3446 /* union */ 3447 3448 /** 3449 * gst_value_can_union: 3450 * @value1: a value to union 3451 * @value2: another value to union 3452 * 3453 * Determines if @value1 and @value2 can be non-trivially unioned. 3454 * Any two values can be trivially unioned by adding both of them 3455 * to a GstValueList. However, certain types have the possibility 3456 * to be unioned in a simpler way. For example, an integer range 3457 * and an integer can be unioned if the integer is a subset of the 3458 * integer range. If there is the possibility that two values can 3459 * be unioned, this function returns TRUE. 3460 * 3461 * Returns: TRUE if there is a function allowing the two values to 3462 * be unioned. 3463 */ 3464 gboolean 3465 gst_value_can_union (const GValue * value1, const GValue * value2) 3466 { 3467 GstValueUnionInfo *union_info; 3468 guint i, len; 3469 3470 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 3471 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 3472 3473 len = gst_value_union_funcs->len; 3474 3475 for (i = 0; i < len; i++) { 3476 union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i); 3477 if (union_info->type1 == G_VALUE_TYPE (value1) && 3478 union_info->type2 == G_VALUE_TYPE (value2)) 3479 return TRUE; 3480 if (union_info->type1 == G_VALUE_TYPE (value2) && 3481 union_info->type2 == G_VALUE_TYPE (value1)) 3482 return TRUE; 3483 } 3484 3485 return FALSE; 3486 } 3487 3488 /** 3489 * gst_value_union: 3490 * @dest: (out caller-allocates): the destination value 3491 * @value1: a value to union 3492 * @value2: another value to union 3493 * 3494 * Creates a GValue corresponding to the union of @value1 and @value2. 3495 * 3496 * Returns: always returns %TRUE 3497 */ 3498 /* FIXME: change return type to 'void'? */ 3499 gboolean 3500 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2) 3501 { 3502 GstValueUnionInfo *union_info; 3503 guint i, len; 3504 3505 g_return_val_if_fail (dest != NULL, FALSE); 3506 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 3507 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 3508 3509 len = gst_value_union_funcs->len; 3510 3511 for (i = 0; i < len; i++) { 3512 union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i); 3513 if (union_info->type1 == G_VALUE_TYPE (value1) && 3514 union_info->type2 == G_VALUE_TYPE (value2)) { 3515 if (union_info->func (dest, value1, value2)) { 3516 return TRUE; 3517 } 3518 } 3519 if (union_info->type1 == G_VALUE_TYPE (value2) && 3520 union_info->type2 == G_VALUE_TYPE (value1)) { 3521 if (union_info->func (dest, value2, value1)) { 3522 return TRUE; 3523 } 3524 } 3525 } 3526 3527 gst_value_list_concat (dest, value1, value2); 3528 return TRUE; 3529 } 3530 3531 /** 3532 * gst_value_register_union_func: 3533 * @type1: a type to union 3534 * @type2: another type to union 3535 * @func: a function that implments creating a union between the two types 3536 * 3537 * Registers a union function that can create a union between #GValue items 3538 * of the type @type1 and @type2. 3539 * 3540 * Union functions should be registered at startup before any pipelines are 3541 * started, as gst_value_register_union_func() is not thread-safe and cannot 3542 * be used at the same time as gst_value_union() or gst_value_can_union(). 3543 */ 3544 void 3545 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func) 3546 { 3547 GstValueUnionInfo union_info; 3548 3549 union_info.type1 = type1; 3550 union_info.type2 = type2; 3551 union_info.func = func; 3552 3553 g_array_append_val (gst_value_union_funcs, union_info); 3554 } 3555 3556 /* intersection */ 3557 3558 /** 3559 * gst_value_can_intersect: 3560 * @value1: a value to intersect 3561 * @value2: another value to intersect 3562 * 3563 * Determines if intersecting two values will produce a valid result. 3564 * Two values will produce a valid intersection if they have the same 3565 * type, or if there is a method (registered by 3566 * gst_value_register_intersect_func()) to calculate the intersection. 3567 * 3568 * Returns: TRUE if the values can intersect 3569 */ 3570 gboolean 3571 gst_value_can_intersect (const GValue * value1, const GValue * value2) 3572 { 3573 GstValueIntersectInfo *intersect_info; 3574 guint i, len; 3575 GType ltype, type1, type2; 3576 3577 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 3578 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 3579 3580 ltype = gst_value_list_get_type (); 3581 3582 /* special cases */ 3583 if (G_VALUE_HOLDS (value1, ltype) || G_VALUE_HOLDS (value2, ltype)) 3584 return TRUE; 3585 3586 type1 = G_VALUE_TYPE (value1); 3587 type2 = G_VALUE_TYPE (value2); 3588 3589 /* practically all GstValue types have a compare function (_can_compare=TRUE) 3590 * GstStructure and GstCaps have npot, but are intersectable */ 3591 if (type1 == type2) 3592 return TRUE; 3593 3594 /* check registered intersect functions */ 3595 len = gst_value_intersect_funcs->len; 3596 for (i = 0; i < len; i++) { 3597 intersect_info = &g_array_index (gst_value_intersect_funcs, 3598 GstValueIntersectInfo, i); 3599 if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) || 3600 (intersect_info->type1 == type2 && intersect_info->type2 == type1)) 3601 return TRUE; 3602 } 3603 3604 return gst_value_can_compare (value1, value2); 3605 } 3606 3607 /** 3608 * gst_value_intersect: 3609 * @dest: (out caller-allocates): a uninitialized #GValue that will hold the calculated 3610 * intersection value 3611 * @value1: a value to intersect 3612 * @value2: another value to intersect 3613 * 3614 * Calculates the intersection of two values. If the values have 3615 * a non-empty intersection, the value representing the intersection 3616 * is placed in @dest. If the intersection is non-empty, @dest is 3617 * not modified. 3618 * 3619 * Returns: TRUE if the intersection is non-empty 3620 */ 3621 gboolean 3622 gst_value_intersect (GValue * dest, const GValue * value1, 3623 const GValue * value2) 3624 { 3625 GstValueIntersectInfo *intersect_info; 3626 guint i, len; 3627 GType ltype, type1, type2; 3628 3629 g_return_val_if_fail (dest != NULL, FALSE); 3630 g_return_val_if_fail (G_IS_VALUE (value1), FALSE); 3631 g_return_val_if_fail (G_IS_VALUE (value2), FALSE); 3632 3633 ltype = gst_value_list_get_type (); 3634 3635 /* special cases first */ 3636 if (G_VALUE_HOLDS (value1, ltype)) 3637 return gst_value_intersect_list (dest, value1, value2); 3638 if (G_VALUE_HOLDS (value2, ltype)) 3639 return gst_value_intersect_list (dest, value2, value1); 3640 3641 if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) { 3642 gst_value_init_and_copy (dest, value1); 3643 return TRUE; 3644 } 3645 3646 type1 = G_VALUE_TYPE (value1); 3647 type2 = G_VALUE_TYPE (value2); 3648 3649 len = gst_value_intersect_funcs->len; 3650 for (i = 0; i < len; i++) { 3651 intersect_info = &g_array_index (gst_value_intersect_funcs, 3652 GstValueIntersectInfo, i); 3653 if (intersect_info->type1 == type1 && intersect_info->type2 == type2) { 3654 return intersect_info->func (dest, value1, value2); 3655 } 3656 if (intersect_info->type1 == type2 && intersect_info->type2 == type1) { 3657 return intersect_info->func (dest, value2, value1); 3658 } 3659 } 3660 return FALSE; 3661 } 3662 3663 /** 3664 * gst_value_register_intersect_func: 3665 * @type1: the first type to intersect 3666 * @type2: the second type to intersect 3667 * @func: the intersection function 3668 * 3669 * Registers a function that is called to calculate the intersection 3670 * of the values having the types @type1 and @type2. 3671 * 3672 * Intersect functions should be registered at startup before any pipelines are 3673 * started, as gst_value_register_intersect_func() is not thread-safe and 3674 * cannot be used at the same time as gst_value_intersect() or 3675 * gst_value_can_intersect(). 3676 */ 3677 void 3678 gst_value_register_intersect_func (GType type1, GType type2, 3679 GstValueIntersectFunc func) 3680 { 3681 GstValueIntersectInfo intersect_info; 3682 3683 intersect_info.type1 = type1; 3684 intersect_info.type2 = type2; 3685 intersect_info.func = func; 3686 3687 g_array_append_val (gst_value_intersect_funcs, intersect_info); 3688 } 3689 3690 3691 /* subtraction */ 3692 3693 /** 3694 * gst_value_subtract: 3695 * @dest: (out caller-allocates): the destination value for the result if the 3696 * subtraction is not empty 3697 * @minuend: the value to subtract from 3698 * @subtrahend: the value to subtract 3699 * 3700 * Subtracts @subtrahend from @minuend and stores the result in @dest. 3701 * Note that this means subtraction as in sets, not as in mathematics. 3702 * 3703 * Returns: %TRUE if the subtraction is not empty 3704 */ 3705 gboolean 3706 gst_value_subtract (GValue * dest, const GValue * minuend, 3707 const GValue * subtrahend) 3708 { 3709 GstValueSubtractInfo *info; 3710 guint i, len; 3711 GType ltype, mtype, stype; 3712 3713 g_return_val_if_fail (dest != NULL, FALSE); 3714 g_return_val_if_fail (G_IS_VALUE (minuend), FALSE); 3715 g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE); 3716 3717 ltype = gst_value_list_get_type (); 3718 3719 /* special cases first */ 3720 if (G_VALUE_HOLDS (minuend, ltype)) 3721 return gst_value_subtract_from_list (dest, minuend, subtrahend); 3722 if (G_VALUE_HOLDS (subtrahend, ltype)) 3723 return gst_value_subtract_list (dest, minuend, subtrahend); 3724 3725 mtype = G_VALUE_TYPE (minuend); 3726 stype = G_VALUE_TYPE (subtrahend); 3727 3728 len = gst_value_subtract_funcs->len; 3729 for (i = 0; i < len; i++) { 3730 info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i); 3731 if (info->minuend == mtype && info->subtrahend == stype) { 3732 return info->func (dest, minuend, subtrahend); 3733 } 3734 } 3735 3736 if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) { 3737 gst_value_init_and_copy (dest, minuend); 3738 return TRUE; 3739 } 3740 3741 return FALSE; 3742 } 3743 3744 #if 0 3745 gboolean 3746 gst_value_subtract (GValue * dest, const GValue * minuend, 3747 const GValue * subtrahend) 3748 { 3749 gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend); 3750 3751 g_printerr ("\"%s\" - \"%s\" = \"%s\"\n", gst_value_serialize (minuend), 3752 gst_value_serialize (subtrahend), 3753 ret ? gst_value_serialize (dest) : "---"); 3754 return ret; 3755 } 3756 #endif 3757 3758 /** 3759 * gst_value_can_subtract: 3760 * @minuend: the value to subtract from 3761 * @subtrahend: the value to subtract 3762 * 3763 * Checks if it's possible to subtract @subtrahend from @minuend. 3764 * 3765 * Returns: TRUE if a subtraction is possible 3766 */ 3767 gboolean 3768 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend) 3769 { 3770 GstValueSubtractInfo *info; 3771 guint i, len; 3772 GType ltype, mtype, stype; 3773 3774 g_return_val_if_fail (G_IS_VALUE (minuend), FALSE); 3775 g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE); 3776 3777 ltype = gst_value_list_get_type (); 3778 3779 /* special cases */ 3780 if (G_VALUE_HOLDS (minuend, ltype) || G_VALUE_HOLDS (subtrahend, ltype)) 3781 return TRUE; 3782 3783 mtype = G_VALUE_TYPE (minuend); 3784 stype = G_VALUE_TYPE (subtrahend); 3785 3786 len = gst_value_subtract_funcs->len; 3787 for (i = 0; i < len; i++) { 3788 info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i); 3789 if (info->minuend == mtype && info->subtrahend == stype) 3790 return TRUE; 3791 } 3792 3793 return gst_value_can_compare (minuend, subtrahend); 3794 } 3795 3796 /** 3797 * gst_value_register_subtract_func: 3798 * @minuend_type: type of the minuend 3799 * @subtrahend_type: type of the subtrahend 3800 * @func: function to use 3801 * 3802 * Registers @func as a function capable of subtracting the values of 3803 * @subtrahend_type from values of @minuend_type. 3804 * 3805 * Subtract functions should be registered at startup before any pipelines are 3806 * started, as gst_value_register_subtract_func() is not thread-safe and 3807 * cannot be used at the same time as gst_value_subtract(). 3808 */ 3809 void 3810 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type, 3811 GstValueSubtractFunc func) 3812 { 3813 GstValueSubtractInfo info; 3814 3815 /* one type must be unfixed, other subtractions can be done as comparisons */ 3816 g_return_if_fail (!gst_type_is_fixed (minuend_type) 3817 || !gst_type_is_fixed (subtrahend_type)); 3818 3819 info.minuend = minuend_type; 3820 info.subtrahend = subtrahend_type; 3821 info.func = func; 3822 3823 g_array_append_val (gst_value_subtract_funcs, info); 3824 } 3825 3826 /** 3827 * gst_value_register: 3828 * @table: structure containing functions to register 3829 * 3830 * Registers functions to perform calculations on #GValue items of a given 3831 * type. Each type can only be added once. 3832 */ 3833 void 3834 gst_value_register (const GstValueTable * table) 3835 { 3836 GstValueTable *found; 3837 3838 g_return_if_fail (table != NULL); 3839 3840 g_array_append_val (gst_value_table, *table); 3841 3842 found = gst_value_hash_lookup_type (table->type); 3843 if (found) 3844 g_warning ("adding type %s multiple times", g_type_name (table->type)); 3845 3846 /* FIXME: we're not really doing the const justice, we assume the table is 3847 * static */ 3848 gst_value_hash_add_type (table->type, table); 3849 } 3850 3851 /** 3852 * gst_value_init_and_copy: 3853 * @dest: (out caller-allocates): the target value 3854 * @src: the source value 3855 * 3856 * Initialises the target value to be of the same type as source and then copies 3857 * the contents from source to target. 3858 */ 3859 void 3860 gst_value_init_and_copy (GValue * dest, const GValue * src) 3861 { 3862 g_return_if_fail (G_IS_VALUE (src)); 3863 g_return_if_fail (dest != NULL); 3864 #ifdef GSTREAMER_LITE 3865 if (src == NULL || !G_IS_VALUE (src) || dest == NULL) 3866 return; 3867 #endif // GSTREAMER_LITE 3868 3869 g_value_init (dest, G_VALUE_TYPE (src)); 3870 g_value_copy (src, dest); 3871 } 3872 3873 /** 3874 * gst_value_serialize: 3875 * @value: a #GValue to serialize 3876 * 3877 * tries to transform the given @value into a string representation that allows 3878 * getting back this string later on using gst_value_deserialize(). 3879 * 3880 * Free-function: g_free 3881 * 3882 * Returns: (transfer full): the serialization for @value or NULL if none exists 3883 */ 3884 gchar * 3885 gst_value_serialize (const GValue * value) 3886 { 3887 guint i, len; 3888 GValue s_val = { 0 }; 3889 GstValueTable *table, *best; 3890 gchar *s; 3891 GType type; 3892 3893 g_return_val_if_fail (G_IS_VALUE (value), NULL); 3894 3895 type = G_VALUE_TYPE (value); 3896 3897 best = gst_value_hash_lookup_type (type); 3898 3899 if (G_UNLIKELY (!best || !best->serialize)) { 3900 len = gst_value_table->len; 3901 best = NULL; 3902 for (i = 0; i < len; i++) { 3903 table = &g_array_index (gst_value_table, GstValueTable, i); 3904 if (table->serialize && g_type_is_a (type, table->type)) { 3905 if (!best || g_type_is_a (table->type, best->type)) 3906 best = table; 3907 } 3908 } 3909 } 3910 if (G_LIKELY (best)) 3911 return best->serialize (value); 3912 3913 g_value_init (&s_val, G_TYPE_STRING); 3914 if (g_value_transform (value, &s_val)) { 3915 s = gst_string_wrap (g_value_get_string (&s_val)); 3916 } else { 3917 s = NULL; 3918 } 3919 g_value_unset (&s_val); 3920 3921 return s; 3922 } 3923 3924 /** 3925 * gst_value_deserialize: 3926 * @dest: (out caller-allocates): #GValue to fill with contents of 3927 * deserialization 3928 * @src: string to deserialize 3929 * 3930 * Tries to deserialize a string into the type specified by the given GValue. 3931 * If the operation succeeds, TRUE is returned, FALSE otherwise. 3932 * 3933 * Returns: TRUE on success 3934 */ 3935 gboolean 3936 gst_value_deserialize (GValue * dest, const gchar * src) 3937 { 3938 GstValueTable *table, *best; 3939 guint i, len; 3940 GType type; 3941 3942 g_return_val_if_fail (src != NULL, FALSE); 3943 g_return_val_if_fail (G_IS_VALUE (dest), FALSE); 3944 3945 type = G_VALUE_TYPE (dest); 3946 3947 best = gst_value_hash_lookup_type (type); 3948 if (G_UNLIKELY (!best || !best->deserialize)) { 3949 len = gst_value_table->len; 3950 best = NULL; 3951 for (i = 0; i < len; i++) { 3952 table = &g_array_index (gst_value_table, GstValueTable, i); 3953 if (table->deserialize && g_type_is_a (type, table->type)) { 3954 if (!best || g_type_is_a (table->type, best->type)) 3955 best = table; 3956 } 3957 } 3958 } 3959 if (G_LIKELY (best)) 3960 return best->deserialize (dest, src); 3961 3962 return FALSE; 3963 } 3964 3965 /** 3966 * gst_value_is_fixed: 3967 * @value: the #GValue to check 3968 * 3969 * Tests if the given GValue, if available in a GstStructure (or any other 3970 * container) contains a "fixed" (which means: one value) or an "unfixed" 3971 * (which means: multiple possible values, such as data lists or data 3972 * ranges) value. 3973 * 3974 * Returns: true if the value is "fixed". 3975 */ 3976 3977 gboolean 3978 gst_value_is_fixed (const GValue * value) 3979 { 3980 GType type; 3981 3982 g_return_val_if_fail (G_IS_VALUE (value), FALSE); 3983 3984 type = G_VALUE_TYPE (value); 3985 3986 /* the most common types are just basic plain glib types */ 3987 if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) { 3988 return TRUE; 3989 } 3990 3991 if (type == GST_TYPE_ARRAY) { 3992 gint size, n; 3993 const GValue *kid; 3994 3995 /* check recursively */ 3996 size = gst_value_array_get_size (value); 3997 for (n = 0; n < size; n++) { 3998 kid = gst_value_array_get_value (value, n); 3999 if (!gst_value_is_fixed (kid)) 4000 return FALSE; 4001 } 4002 return TRUE; 4003 } 4004 return gst_type_is_fixed (type); 4005 } 4006 4007 /************ 4008 * fraction * 4009 ************/ 4010 4011 /* helper functions */ 4012 static void 4013 gst_value_init_fraction (GValue * value) 4014 { 4015 value->data[0].v_int = 0; 4016 value->data[1].v_int = 1; 4017 } 4018 4019 static void 4020 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value) 4021 { 4022 dest_value->data[0].v_int = src_value->data[0].v_int; 4023 dest_value->data[1].v_int = src_value->data[1].v_int; 4024 } 4025 4026 static gchar * 4027 gst_value_collect_fraction (GValue * value, guint n_collect_values, 4028 GTypeCValue * collect_values, guint collect_flags) 4029 { 4030 if (n_collect_values != 2) 4031 return g_strdup_printf ("not enough value locations for `%s' passed", 4032 G_VALUE_TYPE_NAME (value)); 4033 if (collect_values[1].v_int == 0) 4034 return g_strdup_printf ("passed '0' as denominator for `%s'", 4035 G_VALUE_TYPE_NAME (value)); 4036 if (collect_values[0].v_int < -G_MAXINT) 4037 return 4038 g_strdup_printf 4039 ("passed value smaller than -G_MAXINT as numerator for `%s'", 4040 G_VALUE_TYPE_NAME (value)); 4041 if (collect_values[1].v_int < -G_MAXINT) 4042 return 4043 g_strdup_printf 4044 ("passed value smaller than -G_MAXINT as denominator for `%s'", 4045 G_VALUE_TYPE_NAME (value)); 4046 4047 gst_value_set_fraction (value, 4048 collect_values[0].v_int, collect_values[1].v_int); 4049 4050 return NULL; 4051 } 4052 4053 static gchar * 4054 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values, 4055 GTypeCValue * collect_values, guint collect_flags) 4056 { 4057 gint *numerator = collect_values[0].v_pointer; 4058 gint *denominator = collect_values[1].v_pointer; 4059 4060 if (!numerator) 4061 return g_strdup_printf ("numerator for `%s' passed as NULL", 4062 G_VALUE_TYPE_NAME (value)); 4063 if (!denominator) 4064 return g_strdup_printf ("denominator for `%s' passed as NULL", 4065 G_VALUE_TYPE_NAME (value)); 4066 4067 *numerator = value->data[0].v_int; 4068 *denominator = value->data[1].v_int; 4069 4070 return NULL; 4071 } 4072 4073 /** 4074 * gst_value_set_fraction: 4075 * @value: a GValue initialized to #GST_TYPE_FRACTION 4076 * @numerator: the numerator of the fraction 4077 * @denominator: the denominator of the fraction 4078 * 4079 * Sets @value to the fraction specified by @numerator over @denominator. 4080 * The fraction gets reduced to the smallest numerator and denominator, 4081 * and if necessary the sign is moved to the numerator. 4082 */ 4083 void 4084 gst_value_set_fraction (GValue * value, gint numerator, gint denominator) 4085 { 4086 gint gcd = 0; 4087 4088 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value)); 4089 g_return_if_fail (denominator != 0); 4090 g_return_if_fail (denominator >= -G_MAXINT); 4091 g_return_if_fail (numerator >= -G_MAXINT); 4092 4093 /* normalize sign */ 4094 if (denominator < 0) { 4095 numerator = -numerator; 4096 denominator = -denominator; 4097 } 4098 4099 /* check for reduction */ 4100 gcd = gst_util_greatest_common_divisor (numerator, denominator); 4101 if (gcd) { 4102 numerator /= gcd; 4103 denominator /= gcd; 4104 } 4105 4106 g_assert (denominator > 0); 4107 4108 value->data[0].v_int = numerator; 4109 value->data[1].v_int = denominator; 4110 } 4111 4112 /** 4113 * gst_value_get_fraction_numerator: 4114 * @value: a GValue initialized to #GST_TYPE_FRACTION 4115 * 4116 * Gets the numerator of the fraction specified by @value. 4117 * 4118 * Returns: the numerator of the fraction. 4119 */ 4120 gint 4121 gst_value_get_fraction_numerator (const GValue * value) 4122 { 4123 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0); 4124 4125 return value->data[0].v_int; 4126 } 4127 4128 /** 4129 * gst_value_get_fraction_denominator: 4130 * @value: a GValue initialized to #GST_TYPE_FRACTION 4131 * 4132 * Gets the denominator of the fraction specified by @value. 4133 * 4134 * Returns: the denominator of the fraction. 4135 */ 4136 gint 4137 gst_value_get_fraction_denominator (const GValue * value) 4138 { 4139 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1); 4140 4141 return value->data[1].v_int; 4142 } 4143 4144 /** 4145 * gst_value_fraction_multiply: 4146 * @product: a GValue initialized to #GST_TYPE_FRACTION 4147 * @factor1: a GValue initialized to #GST_TYPE_FRACTION 4148 * @factor2: a GValue initialized to #GST_TYPE_FRACTION 4149 * 4150 * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets 4151 * @product to the product of the two fractions. 4152 * 4153 * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise. 4154 */ 4155 gboolean 4156 gst_value_fraction_multiply (GValue * product, const GValue * factor1, 4157 const GValue * factor2) 4158 { 4159 gint n1, n2, d1, d2; 4160 gint res_n, res_d; 4161 4162 g_return_val_if_fail (product != NULL, FALSE); 4163 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE); 4164 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE); 4165 4166 n1 = factor1->data[0].v_int; 4167 n2 = factor2->data[0].v_int; 4168 d1 = factor1->data[1].v_int; 4169 d2 = factor2->data[1].v_int; 4170 4171 if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d)) 4172 return FALSE; 4173 4174 gst_value_set_fraction (product, res_n, res_d); 4175 4176 return TRUE; 4177 } 4178 4179 /** 4180 * gst_value_fraction_subtract: 4181 * @dest: a GValue initialized to #GST_TYPE_FRACTION 4182 * @minuend: a GValue initialized to #GST_TYPE_FRACTION 4183 * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION 4184 * 4185 * Subtracts the @subtrahend from the @minuend and sets @dest to the result. 4186 * 4187 * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise. 4188 */ 4189 gboolean 4190 gst_value_fraction_subtract (GValue * dest, 4191 const GValue * minuend, const GValue * subtrahend) 4192 { 4193 gint n1, n2, d1, d2; 4194 gint res_n, res_d; 4195 4196 g_return_val_if_fail (dest != NULL, FALSE); 4197 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE); 4198 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE); 4199 4200 n1 = minuend->data[0].v_int; 4201 n2 = subtrahend->data[0].v_int; 4202 d1 = minuend->data[1].v_int; 4203 d2 = subtrahend->data[1].v_int; 4204 4205 if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d)) 4206 return FALSE; 4207 gst_value_set_fraction (dest, res_n, res_d); 4208 4209 return TRUE; 4210 } 4211 4212 static gchar * 4213 gst_value_serialize_fraction (const GValue * value) 4214 { 4215 gint32 numerator = value->data[0].v_int; 4216 gint32 denominator = value->data[1].v_int; 4217 gboolean positive = TRUE; 4218 4219 /* get the sign and make components absolute */ 4220 if (numerator < 0) { 4221 numerator = -numerator; 4222 positive = !positive; 4223 } 4224 if (denominator < 0) { 4225 denominator = -denominator; 4226 positive = !positive; 4227 } 4228 4229 return g_strdup_printf ("%s%d/%d", 4230 positive ? "" : "-", numerator, denominator); 4231 } 4232 4233 static gboolean 4234 gst_value_deserialize_fraction (GValue * dest, const gchar * s) 4235 { 4236 gint num, den; 4237 gint num_chars; 4238 4239 if (G_UNLIKELY (s == NULL)) 4240 return FALSE; 4241 4242 if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest))) 4243 return FALSE; 4244 4245 if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) { 4246 if (s[num_chars] != 0) 4247 return FALSE; 4248 if (den == 0) 4249 return FALSE; 4250 4251 gst_value_set_fraction (dest, num, den); 4252 return TRUE; 4253 } else if (g_ascii_strcasecmp (s, "1/max") == 0) { 4254 gst_value_set_fraction (dest, 1, G_MAXINT); 4255 return TRUE; 4256 } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) { 4257 if (s[num_chars] != 0) 4258 return FALSE; 4259 gst_value_set_fraction (dest, num, 1); 4260 return TRUE; 4261 } else if (g_ascii_strcasecmp (s, "min") == 0) { 4262 gst_value_set_fraction (dest, -G_MAXINT, 1); 4263 return TRUE; 4264 } else if (g_ascii_strcasecmp (s, "max") == 0) { 4265 gst_value_set_fraction (dest, G_MAXINT, 1); 4266 return TRUE; 4267 } 4268 4269 return FALSE; 4270 } 4271 4272 static void 4273 gst_value_transform_fraction_string (const GValue * src_value, 4274 GValue * dest_value) 4275 { 4276 dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value); 4277 } 4278 4279 static void 4280 gst_value_transform_string_fraction (const GValue * src_value, 4281 GValue * dest_value) 4282 { 4283 if (!gst_value_deserialize_fraction (dest_value, 4284 src_value->data[0].v_pointer)) 4285 /* If the deserialize fails, ensure we leave the fraction in a 4286 * valid, if incorrect, state */ 4287 gst_value_set_fraction (dest_value, 0, 1); 4288 } 4289 4290 static void 4291 gst_value_transform_double_fraction (const GValue * src_value, 4292 GValue * dest_value) 4293 { 4294 gdouble src = g_value_get_double (src_value); 4295 gint n, d; 4296 4297 gst_util_double_to_fraction (src, &n, &d); 4298 gst_value_set_fraction (dest_value, n, d); 4299 } 4300 4301 static void 4302 gst_value_transform_float_fraction (const GValue * src_value, 4303 GValue * dest_value) 4304 { 4305 gfloat src = g_value_get_float (src_value); 4306 gint n, d; 4307 4308 gst_util_double_to_fraction (src, &n, &d); 4309 gst_value_set_fraction (dest_value, n, d); 4310 } 4311 4312 static void 4313 gst_value_transform_fraction_double (const GValue * src_value, 4314 GValue * dest_value) 4315 { 4316 dest_value->data[0].v_double = ((double) src_value->data[0].v_int) / 4317 ((double) src_value->data[1].v_int); 4318 } 4319 4320 static void 4321 gst_value_transform_fraction_float (const GValue * src_value, 4322 GValue * dest_value) 4323 { 4324 dest_value->data[0].v_float = ((float) src_value->data[0].v_int) / 4325 ((float) src_value->data[1].v_int); 4326 } 4327 4328 static gint 4329 gst_value_compare_fraction (const GValue * value1, const GValue * value2) 4330 { 4331 gint n1, n2; 4332 gint d1, d2; 4333 gint ret; 4334 4335 n1 = value1->data[0].v_int; 4336 n2 = value2->data[0].v_int; 4337 d1 = value1->data[1].v_int; 4338 d2 = value2->data[1].v_int; 4339 4340 /* fractions are reduced when set, so we can quickly see if they're equal */ 4341 if (n1 == n2 && d1 == d2) 4342 return GST_VALUE_EQUAL; 4343 4344 if (d1 == 0 && d2 == 0) 4345 return GST_VALUE_UNORDERED; 4346 else if (d1 == 0) 4347 return GST_VALUE_GREATER_THAN; 4348 else if (d2 == 0) 4349 return GST_VALUE_LESS_THAN; 4350 4351 ret = gst_util_fraction_compare (n1, d1, n2, d2); 4352 if (ret == -1) 4353 return GST_VALUE_LESS_THAN; 4354 else if (ret == 1) 4355 return GST_VALUE_GREATER_THAN; 4356 4357 /* Equality can't happen here because we check for that 4358 * first already */ 4359 g_return_val_if_reached (GST_VALUE_UNORDERED); 4360 } 4361 4362 /********* 4363 * GDate * 4364 *********/ 4365 4366 /** 4367 * gst_value_set_date: 4368 * @value: a GValue initialized to GST_TYPE_DATE 4369 * @date: the date to set the value to 4370 * 4371 * Sets the contents of @value to coorespond to @date. The actual 4372 * #GDate structure is copied before it is used. 4373 */ 4374 void 4375 gst_value_set_date (GValue * value, const GDate * date) 4376 { 4377 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE); 4378 g_return_if_fail (g_date_valid (date)); 4379 4380 g_value_set_boxed (value, date); 4381 } 4382 4383 /** 4384 * gst_value_get_date: 4385 * @value: a GValue initialized to GST_TYPE_DATE 4386 * 4387 * Gets the contents of @value. 4388 * 4389 * Returns: (transfer none): the contents of @value 4390 */ 4391 const GDate * 4392 gst_value_get_date (const GValue * value) 4393 { 4394 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL); 4395 4396 return (const GDate *) g_value_get_boxed (value); 4397 } 4398 4399 static gpointer 4400 gst_date_copy (gpointer boxed) 4401 { 4402 const GDate *date = (const GDate *) boxed; 4403 4404 if (!g_date_valid (date)) { 4405 GST_WARNING ("invalid GDate"); 4406 return NULL; 4407 } 4408 4409 return g_date_new_julian (g_date_get_julian (date)); 4410 } 4411 4412 static gint 4413 gst_value_compare_date (const GValue * value1, const GValue * value2) 4414 { 4415 const GDate *date1 = (const GDate *) g_value_get_boxed (value1); 4416 const GDate *date2 = (const GDate *) g_value_get_boxed (value2); 4417 guint32 j1, j2; 4418 4419 if (date1 == date2) 4420 return GST_VALUE_EQUAL; 4421 4422 if ((date1 == NULL || !g_date_valid (date1)) 4423 && (date2 != NULL && g_date_valid (date2))) { 4424 return GST_VALUE_LESS_THAN; 4425 } 4426 4427 if ((date2 == NULL || !g_date_valid (date2)) 4428 && (date1 != NULL && g_date_valid (date1))) { 4429 return GST_VALUE_GREATER_THAN; 4430 } 4431 4432 if (date1 == NULL || date2 == NULL || !g_date_valid (date1) 4433 || !g_date_valid (date2)) { 4434 return GST_VALUE_UNORDERED; 4435 } 4436 4437 j1 = g_date_get_julian (date1); 4438 j2 = g_date_get_julian (date2); 4439 4440 if (j1 == j2) 4441 return GST_VALUE_EQUAL; 4442 else if (j1 < j2) 4443 return GST_VALUE_LESS_THAN; 4444 else 4445 return GST_VALUE_GREATER_THAN; 4446 } 4447 4448 static gchar * 4449 gst_value_serialize_date (const GValue * val) 4450 { 4451 const GDate *date = (const GDate *) g_value_get_boxed (val); 4452 4453 if (date == NULL || !g_date_valid (date)) 4454 return g_strdup ("9999-99-99"); 4455 4456 return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date), 4457 g_date_get_month (date), g_date_get_day (date)); 4458 } 4459 4460 static gboolean 4461 gst_value_deserialize_date (GValue * dest, const gchar * s) 4462 { 4463 guint year, month, day; 4464 4465 if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3) 4466 return FALSE; 4467 4468 if (!g_date_valid_dmy (day, month, year)) 4469 return FALSE; 4470 4471 g_value_take_boxed (dest, g_date_new_dmy (day, month, year)); 4472 return TRUE; 4473 } 4474 4475 /************* 4476 * GstDateTime * 4477 *************/ 4478 4479 static gint 4480 gst_value_compare_date_time (const GValue * value1, const GValue * value2) 4481 { 4482 const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1); 4483 const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2); 4484 gint ret; 4485 4486 if (date1 == date2) 4487 return GST_VALUE_EQUAL; 4488 4489 if ((date1 == NULL) && (date2 != NULL)) { 4490 return GST_VALUE_LESS_THAN; 4491 } 4492 if ((date2 == NULL) && (date1 != NULL)) { 4493 return GST_VALUE_LESS_THAN; 4494 } 4495 4496 ret = priv_gst_date_time_compare (date1, date2); 4497 4498 if (ret == 0) 4499 return GST_VALUE_EQUAL; 4500 else if (ret < 0) 4501 return GST_VALUE_LESS_THAN; 4502 else 4503 return GST_VALUE_GREATER_THAN; 4504 } 4505 4506 static gchar * 4507 gst_value_serialize_date_time (const GValue * val) 4508 { 4509 GstDateTime *date = (GstDateTime *) g_value_get_boxed (val); 4510 gfloat offset; 4511 gint tzhour, tzminute; 4512 4513 if (date == NULL) 4514 return g_strdup ("null"); 4515 4516 offset = gst_date_time_get_time_zone_offset (date); 4517 4518 tzhour = (gint) ABS (offset); 4519 tzminute = (gint) ((ABS (offset) - tzhour) * 60); 4520 4521 return g_strdup_printf ("\"%04d-%02d-%02dT%02d:%02d:%02d.%06d" 4522 "%c%02d%02d\"", gst_date_time_get_year (date), 4523 gst_date_time_get_month (date), gst_date_time_get_day (date), 4524 gst_date_time_get_hour (date), gst_date_time_get_minute (date), 4525 gst_date_time_get_second (date), gst_date_time_get_microsecond (date), 4526 offset >= 0 ? '+' : '-', tzhour, tzminute); 4527 } 4528 4529 static gboolean 4530 gst_value_deserialize_date_time (GValue * dest, const gchar * s) 4531 { 4532 gint year, month, day, hour, minute, second, usecond; 4533 gchar signal; 4534 gint offset = 0; 4535 gfloat tzoffset = 0; 4536 gint ret; 4537 4538 if (!s || strcmp (s, "null") == 0) { 4539 return FALSE; 4540 } 4541 4542 ret = sscanf (s, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%c%04d", 4543 &year, &month, &day, &hour, &minute, &second, &usecond, &signal, &offset); 4544 if (ret >= 9) { 4545 tzoffset = (offset / 100) + ((offset % 100) / 60.0); 4546 if (signal == '-') 4547 tzoffset = -tzoffset; 4548 } else 4549 return FALSE; 4550 4551 g_value_take_boxed (dest, gst_date_time_new (tzoffset, year, month, day, hour, 4552 minute, second + (usecond / 1000000.0))); 4553 return TRUE; 4554 } 4555 4556 static void 4557 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value) 4558 { 4559 dest_value->data[0].v_pointer = gst_value_serialize_date (src_value); 4560 } 4561 4562 static void 4563 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value) 4564 { 4565 gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer); 4566 } 4567 4568 static void 4569 gst_value_transform_object_string (const GValue * src_value, 4570 GValue * dest_value) 4571 { 4572 GstObject *obj; 4573 gchar *str; 4574 4575 obj = g_value_get_object (src_value); 4576 if (obj) { 4577 str = 4578 g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj), 4579 GST_OBJECT_NAME (obj)); 4580 } else { 4581 str = g_strdup ("NULL"); 4582 } 4583 4584 dest_value->data[0].v_pointer = str; 4585 } 4586 4587 static GTypeInfo _info = { 4588 0, 4589 NULL, 4590 NULL, 4591 NULL, 4592 NULL, 4593 NULL, 4594 0, 4595 0, 4596 NULL, 4597 NULL, 4598 }; 4599 4600 static GTypeFundamentalInfo _finfo = { 4601 0 4602 }; 4603 4604 #define FUNC_VALUE_GET_TYPE(type, name) \ 4605 GType gst_ ## type ## _get_type (void) \ 4606 { \ 4607 static volatile GType gst_ ## type ## _type = 0; \ 4608 \ 4609 if (g_once_init_enter (&gst_ ## type ## _type)) { \ 4610 GType _type; \ 4611 _info.value_table = & _gst_ ## type ## _value_table; \ 4612 _type = g_type_register_fundamental ( \ 4613 g_type_fundamental_next (), \ 4614 name, &_info, &_finfo, 0); \ 4615 g_once_init_leave(&gst_ ## type ## _type, _type); \ 4616 } \ 4617 \ 4618 return gst_ ## type ## _type; \ 4619 } 4620 4621 static const GTypeValueTable _gst_fourcc_value_table = { 4622 gst_value_init_fourcc, 4623 NULL, 4624 gst_value_copy_fourcc, 4625 NULL, 4626 (char *) "i", 4627 gst_value_collect_fourcc, 4628 (char *) "p", 4629 gst_value_lcopy_fourcc 4630 }; 4631 4632 FUNC_VALUE_GET_TYPE (fourcc, "GstFourcc"); 4633 4634 static const GTypeValueTable _gst_int_range_value_table = { 4635 gst_value_init_int_range, 4636 NULL, 4637 gst_value_copy_int_range, 4638 NULL, 4639 (char *) "ii", 4640 gst_value_collect_int_range, 4641 (char *) "pp", 4642 gst_value_lcopy_int_range 4643 }; 4644 4645 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange"); 4646 4647 static const GTypeValueTable _gst_int64_range_value_table = { 4648 gst_value_init_int64_range, 4649 NULL, 4650 gst_value_copy_int64_range, 4651 NULL, 4652 (char *) "qq", 4653 gst_value_collect_int64_range, 4654 (char *) "pp", 4655 gst_value_lcopy_int64_range 4656 }; 4657 4658 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range"); 4659 4660 static const GTypeValueTable _gst_double_range_value_table = { 4661 gst_value_init_double_range, 4662 NULL, 4663 gst_value_copy_double_range, 4664 NULL, 4665 (char *) "dd", 4666 gst_value_collect_double_range, 4667 (char *) "pp", 4668 gst_value_lcopy_double_range 4669 }; 4670 4671 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange"); 4672 4673 static const GTypeValueTable _gst_fraction_range_value_table = { 4674 gst_value_init_fraction_range, 4675 gst_value_free_fraction_range, 4676 gst_value_copy_fraction_range, 4677 NULL, 4678 (char *) "iiii", 4679 gst_value_collect_fraction_range, 4680 (char *) "pppp", 4681 gst_value_lcopy_fraction_range 4682 }; 4683 4684 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange"); 4685 4686 static const GTypeValueTable _gst_value_list_value_table = { 4687 gst_value_init_list_or_array, 4688 gst_value_free_list_or_array, 4689 gst_value_copy_list_or_array, 4690 gst_value_list_or_array_peek_pointer, 4691 (char *) "p", 4692 gst_value_collect_list_or_array, 4693 (char *) "p", 4694 gst_value_lcopy_list_or_array 4695 }; 4696 4697 FUNC_VALUE_GET_TYPE (value_list, "GstValueList"); 4698 4699 static const GTypeValueTable _gst_value_array_value_table = { 4700 gst_value_init_list_or_array, 4701 gst_value_free_list_or_array, 4702 gst_value_copy_list_or_array, 4703 gst_value_list_or_array_peek_pointer, 4704 (char *) "p", 4705 gst_value_collect_list_or_array, 4706 (char *) "p", 4707 gst_value_lcopy_list_or_array 4708 }; 4709 4710 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray"); 4711 4712 static const GTypeValueTable _gst_fraction_value_table = { 4713 gst_value_init_fraction, 4714 NULL, 4715 gst_value_copy_fraction, 4716 NULL, 4717 (char *) "ii", 4718 gst_value_collect_fraction, 4719 (char *) "pp", 4720 gst_value_lcopy_fraction 4721 }; 4722 4723 FUNC_VALUE_GET_TYPE (fraction, "GstFraction"); 4724 4725 4726 GType 4727 gst_date_get_type (void) 4728 { 4729 static GType gst_date_type = 0; 4730 4731 if (G_UNLIKELY (gst_date_type == 0)) { 4732 /* FIXME 0.11: we require GLib 2.8 already 4733 * Not using G_TYPE_DATE here on purpose, even if we could 4734 * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the 4735 * serialised strings to have different type strings depending 4736 * on what version is used, so FIXME when we require GLib-2.8 */ 4737 gst_date_type = g_boxed_type_register_static ("GstDate", 4738 (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free); 4739 } 4740 4741 return gst_date_type; 4742 } 4743 4744 GType 4745 gst_date_time_get_type (void) 4746 { 4747 static GType gst_date_time_type = 0; 4748 4749 if (G_UNLIKELY (gst_date_time_type == 0)) { 4750 gst_date_time_type = g_boxed_type_register_static ("GstDateTime", 4751 (GBoxedCopyFunc) gst_date_time_ref, 4752 (GBoxedFreeFunc) gst_date_time_unref); 4753 } 4754 4755 return gst_date_time_type; 4756 } 4757 4758 4759 void 4760 _gst_value_initialize (void) 4761 { 4762 gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable)); 4763 gst_value_hash = g_hash_table_new (NULL, NULL); 4764 gst_value_union_funcs = g_array_new (FALSE, FALSE, 4765 sizeof (GstValueUnionInfo)); 4766 gst_value_intersect_funcs = g_array_new (FALSE, FALSE, 4767 sizeof (GstValueIntersectInfo)); 4768 gst_value_subtract_funcs = g_array_new (FALSE, FALSE, 4769 sizeof (GstValueSubtractInfo)); 4770 4771 { 4772 static GstValueTable gst_value = { 4773 0, 4774 gst_value_compare_fourcc, 4775 gst_value_serialize_fourcc, 4776 gst_value_deserialize_fourcc, 4777 }; 4778 4779 gst_value.type = gst_fourcc_get_type (); 4780 gst_value_register (&gst_value); 4781 } 4782 4783 { 4784 static GstValueTable gst_value = { 4785 0, 4786 gst_value_compare_int_range, 4787 gst_value_serialize_int_range, 4788 gst_value_deserialize_int_range, 4789 }; 4790 4791 gst_value.type = gst_int_range_get_type (); 4792 gst_value_register (&gst_value); 4793 } 4794 4795 { 4796 static GstValueTable gst_value = { 4797 0, 4798 gst_value_compare_int64_range, 4799 gst_value_serialize_int64_range, 4800 gst_value_deserialize_int64_range, 4801 }; 4802 4803 gst_value.type = gst_int64_range_get_type (); 4804 gst_value_register (&gst_value); 4805 } 4806 4807 { 4808 static GstValueTable gst_value = { 4809 0, 4810 gst_value_compare_double_range, 4811 gst_value_serialize_double_range, 4812 gst_value_deserialize_double_range, 4813 }; 4814 4815 gst_value.type = gst_double_range_get_type (); 4816 gst_value_register (&gst_value); 4817 } 4818 4819 { 4820 static GstValueTable gst_value = { 4821 0, 4822 gst_value_compare_fraction_range, 4823 gst_value_serialize_fraction_range, 4824 gst_value_deserialize_fraction_range, 4825 }; 4826 4827 gst_value.type = gst_fraction_range_get_type (); 4828 gst_value_register (&gst_value); 4829 } 4830 4831 { 4832 static GstValueTable gst_value = { 4833 0, 4834 gst_value_compare_list, 4835 gst_value_serialize_list, 4836 gst_value_deserialize_list, 4837 }; 4838 4839 gst_value.type = gst_value_list_get_type (); 4840 gst_value_register (&gst_value); 4841 } 4842 4843 { 4844 static GstValueTable gst_value = { 4845 0, 4846 gst_value_compare_array, 4847 gst_value_serialize_array, 4848 gst_value_deserialize_array, 4849 }; 4850 4851 gst_value.type = gst_value_array_get_type (); 4852 gst_value_register (&gst_value); 4853 } 4854 4855 { 4856 #if 0 4857 static const GTypeValueTable value_table = { 4858 gst_value_init_buffer, 4859 NULL, 4860 gst_value_copy_buffer, 4861 NULL, 4862 "i", 4863 NULL, /*gst_value_collect_buffer, */ 4864 "p", 4865 NULL /*gst_value_lcopy_buffer */ 4866 }; 4867 #endif 4868 static GstValueTable gst_value = { 4869 0, 4870 gst_value_compare_buffer, 4871 gst_value_serialize_buffer, 4872 gst_value_deserialize_buffer, 4873 }; 4874 4875 gst_value.type = GST_TYPE_BUFFER; 4876 gst_value_register (&gst_value); 4877 } 4878 { 4879 static GstValueTable gst_value = { 4880 0, 4881 gst_value_compare_fraction, 4882 gst_value_serialize_fraction, 4883 gst_value_deserialize_fraction, 4884 }; 4885 4886 gst_value.type = gst_fraction_get_type (); 4887 gst_value_register (&gst_value); 4888 } 4889 { 4890 static GstValueTable gst_value = { 4891 0, 4892 NULL, 4893 gst_value_serialize_caps, 4894 gst_value_deserialize_caps, 4895 }; 4896 4897 gst_value.type = GST_TYPE_CAPS; 4898 gst_value_register (&gst_value); 4899 } 4900 { 4901 static GstValueTable gst_value = { 4902 0, 4903 NULL, 4904 gst_value_serialize_structure, 4905 gst_value_deserialize_structure, 4906 }; 4907 4908 gst_value.type = GST_TYPE_STRUCTURE; 4909 gst_value_register (&gst_value); 4910 } 4911 { 4912 static GstValueTable gst_value = { 4913 0, 4914 gst_value_compare_date, 4915 gst_value_serialize_date, 4916 gst_value_deserialize_date, 4917 }; 4918 4919 gst_value.type = gst_date_get_type (); 4920 gst_value_register (&gst_value); 4921 } 4922 { 4923 static GstValueTable gst_value = { 4924 0, 4925 gst_value_compare_date_time, 4926 gst_value_serialize_date_time, 4927 gst_value_deserialize_date_time, 4928 }; 4929 4930 gst_value.type = gst_date_time_get_type (); 4931 gst_value_register (&gst_value); 4932 } 4933 4934 REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double); 4935 REGISTER_SERIALIZATION (G_TYPE_FLOAT, float); 4936 4937 REGISTER_SERIALIZATION (G_TYPE_STRING, string); 4938 REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean); 4939 REGISTER_SERIALIZATION (G_TYPE_ENUM, enum); 4940 4941 REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags); 4942 4943 REGISTER_SERIALIZATION (G_TYPE_INT, int); 4944 4945 REGISTER_SERIALIZATION (G_TYPE_INT64, int64); 4946 REGISTER_SERIALIZATION (G_TYPE_LONG, long); 4947 4948 REGISTER_SERIALIZATION (G_TYPE_UINT, uint); 4949 REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64); 4950 REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong); 4951 4952 REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar); 4953 4954 g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING, 4955 gst_value_transform_fourcc_string); 4956 g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING, 4957 gst_value_transform_int_range_string); 4958 g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING, 4959 gst_value_transform_int64_range_string); 4960 g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING, 4961 gst_value_transform_double_range_string); 4962 g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING, 4963 gst_value_transform_fraction_range_string); 4964 g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING, 4965 gst_value_transform_list_string); 4966 g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING, 4967 gst_value_transform_array_string); 4968 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING, 4969 gst_value_transform_fraction_string); 4970 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION, 4971 gst_value_transform_string_fraction); 4972 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE, 4973 gst_value_transform_fraction_double); 4974 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT, 4975 gst_value_transform_fraction_float); 4976 g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION, 4977 gst_value_transform_double_fraction); 4978 g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION, 4979 gst_value_transform_float_fraction); 4980 g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING, 4981 gst_value_transform_date_string); 4982 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE, 4983 gst_value_transform_string_date); 4984 g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING, 4985 gst_value_transform_object_string); 4986 4987 gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE, 4988 gst_value_intersect_int_int_range); 4989 gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, 4990 gst_value_intersect_int_range_int_range); 4991 gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE, 4992 gst_value_intersect_int64_int64_range); 4993 gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE, 4994 gst_value_intersect_int64_range_int64_range); 4995 gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, 4996 gst_value_intersect_double_double_range); 4997 gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE, 4998 GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range); 4999 gst_value_register_intersect_func (GST_TYPE_ARRAY, 5000 GST_TYPE_ARRAY, gst_value_intersect_array); 5001 gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 5002 gst_value_intersect_fraction_fraction_range); 5003 gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE, 5004 GST_TYPE_FRACTION_RANGE, 5005 gst_value_intersect_fraction_range_fraction_range); 5006 5007 gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE, 5008 gst_value_subtract_int_int_range); 5009 gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT, 5010 gst_value_subtract_int_range_int); 5011 gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, 5012 gst_value_subtract_int_range_int_range); 5013 gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE, 5014 gst_value_subtract_int64_int64_range); 5015 gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64, 5016 gst_value_subtract_int64_range_int64); 5017 gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE, 5018 gst_value_subtract_int64_range_int64_range); 5019 gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, 5020 gst_value_subtract_double_double_range); 5021 gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE, 5022 gst_value_subtract_double_range_double); 5023 gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, 5024 GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range); 5025 5026 gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 5027 gst_value_subtract_fraction_fraction_range); 5028 gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION, 5029 gst_value_subtract_fraction_range_fraction); 5030 gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, 5031 GST_TYPE_FRACTION_RANGE, 5032 gst_value_subtract_fraction_range_fraction_range); 5033 5034 /* see bug #317246, #64994, #65041 */ 5035 { 5036 volatile GType date_type = G_TYPE_DATE; 5037 5038 g_type_name (date_type); 5039 } 5040 5041 gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE, 5042 gst_value_union_int_int_range); 5043 gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE, 5044 gst_value_union_int_range_int_range); 5045 5046 #if 0 5047 /* Implement these if needed */ 5048 gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 5049 gst_value_union_fraction_fraction_range); 5050 gst_value_register_union_func (GST_TYPE_FRACTION_RANGE, 5051 GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range); 5052 #endif 5053 }