3 * \brief Property class definition
6 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "mlt_property.h"
38 /** Bit pattern used internally to indicated representations available.
43 mlt_prop_none = 0, //!< not set
44 mlt_prop_int = 1, //!< set as an integer
45 mlt_prop_string = 2, //!< set as string or already converted to string
46 mlt_prop_position = 4,//!< set as a position
47 mlt_prop_double = 8, //!< set as a floating point
48 mlt_prop_data = 16, //!< set as opaque binary
49 mlt_prop_int64 = 32 //!< set as a 64-bit integer
53 /** \brief Property class
55 * A property is like a variant or dynamic type. They are used for many things
56 * in MLT, but in particular they are the parameter mechanism for the plugins.
61 /// Stores a bit pattern of types available for this property
62 mlt_property_type types;
64 /// Atomic type handling
66 mlt_position prop_position;
73 /// Generic type handling
76 mlt_destructor destructor;
77 mlt_serialiser serialiser;
79 pthread_mutex_t mutex;
82 /** Construct a property and initialize it
83 * \public \memberof mlt_property_s
86 mlt_property mlt_property_init( )
88 mlt_property self = malloc( sizeof( struct mlt_property_s ) );
93 self->prop_position = 0;
94 self->prop_double = 0;
96 self->prop_string = NULL;
99 self->destructor = NULL;
100 self->serialiser = NULL;
101 pthread_mutex_init( &self->mutex, NULL );
106 /** Clear (0/null) a property.
108 * Frees up any associated resources in the process.
109 * \private \memberof mlt_property_s
110 * \param self a property
113 static inline void mlt_property_clear( mlt_property self )
115 // Special case data handling
116 if ( self->types & mlt_prop_data && self->destructor != NULL )
117 self->destructor( self->data );
119 // Special case string handling
120 if ( self->types & mlt_prop_string )
121 free( self->prop_string );
126 self->prop_position = 0;
127 self->prop_double = 0;
128 self->prop_int64 = 0;
129 self->prop_string = NULL;
132 self->destructor = NULL;
133 self->serialiser = NULL;
136 /** Set the property to an integer value.
138 * \public \memberof mlt_property_s
139 * \param self a property
140 * \param value an integer
144 int mlt_property_set_int( mlt_property self, int value )
146 mlt_property_clear( self );
147 self->types = mlt_prop_int;
148 self->prop_int = value;
152 /** Set the property to a floating point value.
154 * \public \memberof mlt_property_s
155 * \param self a property
156 * \param value a double precision floating point value
160 int mlt_property_set_double( mlt_property self, double value )
162 mlt_property_clear( self );
163 self->types = mlt_prop_double;
164 self->prop_double = value;
168 /** Set the property to a position value.
170 * Position is a relative time value in frame units.
171 * \public \memberof mlt_property_s
172 * \param self a property
173 * \param value a position value
177 int mlt_property_set_position( mlt_property self, mlt_position value )
179 mlt_property_clear( self );
180 self->types = mlt_prop_position;
181 self->prop_position = value;
185 /** Set the property to a string value.
187 * This makes a copy of the string you supply so you do not need to track
188 * a new reference to it.
189 * \public \memberof mlt_property_s
190 * \param self a property
191 * \param value the string to copy to the property
192 * \return true if it failed
195 int mlt_property_set_string( mlt_property self, const char *value )
197 if ( value != self->prop_string )
199 mlt_property_clear( self );
200 self->types = mlt_prop_string;
202 self->prop_string = strdup( value );
206 self->types = mlt_prop_string;
208 return self->prop_string == NULL;
211 /** Set the property to a 64-bit integer value.
213 * \public \memberof mlt_property_s
214 * \param self a property
215 * \param value a 64-bit integer
219 int mlt_property_set_int64( mlt_property self, int64_t value )
221 mlt_property_clear( self );
222 self->types = mlt_prop_int64;
223 self->prop_int64 = value;
227 /** Set a property to an opaque binary value.
229 * This does not make a copy of the data. You can use a Properties object
230 * with its reference tracking and the destructor function to control
231 * the lifetime of the data. Otherwise, pass NULL for the destructor
232 * function and control the lifetime yourself.
233 * \public \memberof mlt_property_s
234 * \param self a property
235 * \param value an opaque pointer
236 * \param length the number of bytes pointed to by value (optional)
237 * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource)
238 * \param serialiser a function to use to convert this binary data to a string (optional)
242 int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
244 if ( self->data == value )
245 self->destructor = NULL;
246 mlt_property_clear( self );
247 self->types = mlt_prop_data;
249 self->length = length;
250 self->destructor = destructor;
251 self->serialiser = serialiser;
255 /** Convert a base 10 or base 16 string to an integer.
257 * The string must begin with '0x' to be interpreted as hexadecimal.
258 * Otherwise, it is interpreted as base 10.
259 * If the string begins with '#' it is interpreted as a hexadecimal color value
260 * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
261 * always in the form RRGGBBAA where the alpha components are not optional.
262 * Applications and services should expect the binary color value in bytes to
263 * be in the following order: RGBA. This means they will have to cast the int
264 * to an unsigned int. This is especially important when they need to shift
265 * right to obtain RGB without alpha in order to make it do a logical instead
266 * of arithmetic shift.
268 * \private \memberof mlt_property_s
269 * \param value a string to convert
270 * \return the resultant integer
272 static inline int mlt_property_atoi( const char *value )
276 // Parse a hex color value as #RRGGBB or #AARRGGBB.
277 if ( value[0] == '#' )
279 unsigned int rgb = strtoul( value + 1, NULL, 16 );
280 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
281 return ( rgb << 8 ) | alpha;
283 // Do hex and decimal explicitly to avoid decimal value with leading zeros
284 // interpreted as octal.
285 else if ( value[0] == '0' && value[1] == 'x' )
287 return strtoul( value + 2, NULL, 16 );
291 return strtol( value, NULL, 10 );
295 /** Get the property as an integer.
297 * \public \memberof mlt_property_s
298 * \param self a property
299 * \return an integer value
302 int mlt_property_get_int( mlt_property self )
304 if ( self->types & mlt_prop_int )
305 return self->prop_int;
306 else if ( self->types & mlt_prop_double )
307 return ( int )self->prop_double;
308 else if ( self->types & mlt_prop_position )
309 return ( int )self->prop_position;
310 else if ( self->types & mlt_prop_int64 )
311 return ( int )self->prop_int64;
312 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
313 return mlt_property_atoi( self->prop_string );
317 /** Get the property as a floating point.
319 * \public \memberof mlt_property_s
320 * \param self a property
321 * \return a floating point value
324 double mlt_property_get_double( mlt_property self )
326 if ( self->types & mlt_prop_double )
327 return self->prop_double;
328 else if ( self->types & mlt_prop_int )
329 return ( double )self->prop_int;
330 else if ( self->types & mlt_prop_position )
331 return ( double )self->prop_position;
332 else if ( self->types & mlt_prop_int64 )
333 return ( double )self->prop_int64;
334 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
335 return atof( self->prop_string );
339 /** Get the property (with locale) as a floating point.
341 * \public \memberof mlt_property_s
342 * \param self a property
343 * \param locale the locale to use for this conversion
344 * \return a floating point value
347 double mlt_property_get_double_l( mlt_property self, locale_t locale )
349 if ( self->types & mlt_prop_double )
350 return self->prop_double;
351 else if ( self->types & mlt_prop_int )
352 return ( double )self->prop_int;
353 else if ( self->types & mlt_prop_position )
354 return ( double )self->prop_position;
355 else if ( self->types & mlt_prop_int64 )
356 return ( double )self->prop_int64;
357 #if defined(__GLIBC__) || defined(__DARWIN__)
358 else if ( locale && ( self->types & mlt_prop_string ) && self->prop_string )
359 return strtod_l( self->prop_string, NULL, locale );
361 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
362 return strtod( self->prop_string, NULL );
366 /** Get the property as a position.
368 * A position is an offset time in terms of frame units.
369 * \public \memberof mlt_property_s
370 * \param self a property
371 * \return the position in frames
374 mlt_position mlt_property_get_position( mlt_property self )
376 if ( self->types & mlt_prop_position )
377 return self->prop_position;
378 else if ( self->types & mlt_prop_int )
379 return ( mlt_position )self->prop_int;
380 else if ( self->types & mlt_prop_double )
381 return ( mlt_position )self->prop_double;
382 else if ( self->types & mlt_prop_int64 )
383 return ( mlt_position )self->prop_int64;
384 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
385 return ( mlt_position )atol( self->prop_string );
389 /** Convert a string to a 64-bit integer.
391 * If the string begins with '0x' it is interpreted as a hexadecimal value.
392 * \private \memberof mlt_property_s
393 * \param value a string
394 * \return a 64-bit integer
397 static inline int64_t mlt_property_atoll( const char *value )
401 else if ( value[0] == '0' && value[1] == 'x' )
402 return strtoll( value + 2, NULL, 16 );
404 return strtoll( value, NULL, 10 );
407 /** Get the property as a signed integer.
409 * \public \memberof mlt_property_s
410 * \param self a property
411 * \return a 64-bit integer
414 int64_t mlt_property_get_int64( mlt_property self )
416 if ( self->types & mlt_prop_int64 )
417 return self->prop_int64;
418 else if ( self->types & mlt_prop_int )
419 return ( int64_t )self->prop_int;
420 else if ( self->types & mlt_prop_double )
421 return ( int64_t )self->prop_double;
422 else if ( self->types & mlt_prop_position )
423 return ( int64_t )self->prop_position;
424 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
425 return mlt_property_atoll( self->prop_string );
429 /** Get the property as a string.
431 * The caller is not responsible for deallocating the returned string!
432 * The string is deallocated when the Property is closed.
433 * This tries its hardest to convert the property to string including using
434 * a serialization function for binary data, if supplied.
435 * \public \memberof mlt_property_s
436 * \param self a property
437 * \return a string representation of the property or NULL if failed
440 char *mlt_property_get_string( mlt_property self )
442 // Construct a string if need be
443 if ( ! ( self->types & mlt_prop_string ) )
445 if ( self->types & mlt_prop_int )
447 self->types |= mlt_prop_string;
448 self->prop_string = malloc( 32 );
449 sprintf( self->prop_string, "%d", self->prop_int );
451 else if ( self->types & mlt_prop_double )
453 self->types |= mlt_prop_string;
454 self->prop_string = malloc( 32 );
455 sprintf( self->prop_string, "%f", self->prop_double );
457 else if ( self->types & mlt_prop_position )
459 self->types |= mlt_prop_string;
460 self->prop_string = malloc( 32 );
461 sprintf( self->prop_string, "%d", (int)self->prop_position );
463 else if ( self->types & mlt_prop_int64 )
465 self->types |= mlt_prop_string;
466 self->prop_string = malloc( 32 );
467 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
469 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
471 self->types |= mlt_prop_string;
472 self->prop_string = self->serialiser( self->data, self->length );
476 // Return the string (may be NULL)
477 return self->prop_string;
480 /** Get the property as a string (with locale).
482 * The caller is not responsible for deallocating the returned string!
483 * The string is deallocated when the Property is closed.
484 * This tries its hardest to convert the property to string including using
485 * a serialization function for binary data, if supplied.
486 * \public \memberof mlt_property_s
487 * \param self a property
488 * \param locale the locale to use for this conversion
489 * \return a string representation of the property or NULL if failed
492 char *mlt_property_get_string_l( mlt_property self, locale_t locale )
494 // Optimization for no locale
496 return mlt_property_get_string( self );
498 // Construct a string if need be
499 if ( ! ( self->types & mlt_prop_string ) )
501 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
502 // Save the current locale
503 #if defined(__DARWIN__)
504 const char *localename = querylocale( LC_NUMERIC, locale );
505 #elif defined(__GLIBC__)
506 const char *localename = locale->__names[ LC_NUMERIC ];
508 // TODO: not yet sure what to do on other platforms
509 const char *localename = "";
511 // Protect damaging the global locale from a temporary locale on another thread.
512 pthread_mutex_lock( &self->mutex );
514 // Get the current locale
515 const char *orig_localename = setlocale( LC_NUMERIC, NULL );
517 // Set the new locale
518 setlocale( LC_NUMERIC, localename );
520 if ( self->types & mlt_prop_int )
522 self->types |= mlt_prop_string;
523 self->prop_string = malloc( 32 );
524 sprintf( self->prop_string, "%d", self->prop_int );
526 else if ( self->types & mlt_prop_double )
528 self->types |= mlt_prop_string;
529 self->prop_string = malloc( 32 );
530 sprintf( self->prop_string, "%f", self->prop_double );
532 else if ( self->types & mlt_prop_position )
534 self->types |= mlt_prop_string;
535 self->prop_string = malloc( 32 );
536 sprintf( self->prop_string, "%d", (int)self->prop_position );
538 else if ( self->types & mlt_prop_int64 )
540 self->types |= mlt_prop_string;
541 self->prop_string = malloc( 32 );
542 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
544 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
546 self->types |= mlt_prop_string;
547 self->prop_string = self->serialiser( self->data, self->length );
549 // Restore the current locale
550 setlocale( LC_NUMERIC, orig_localename );
551 pthread_mutex_unlock( &self->mutex );
554 // Return the string (may be NULL)
555 return self->prop_string;
558 /** Get the binary data from a property.
560 * This only works if you previously put binary data into the property.
561 * This does not return a copy of the data; it returns a pointer to it.
562 * If you supplied a destructor function when setting the binary data,
563 * the destructor is used when the Property is closed to free the memory.
564 * Therefore, only free the returned pointer if you did not supply a
565 * destructor function.
566 * \public \memberof mlt_property_s
567 * \param self a property
568 * \param[out] length the size of the binary object in bytes (optional)
569 * \return an opaque data pointer or NULL if not available
572 void *mlt_property_get_data( mlt_property self, int *length )
574 // Assign length if not NULL
575 if ( length != NULL )
576 *length = self->length;
578 // Return the data (note: there is no conversion here)
582 /** Destroy a property and free all related resources.
584 * \public \memberof mlt_property_s
585 * \param self a property
588 void mlt_property_close( mlt_property self )
590 mlt_property_clear( self );
591 pthread_mutex_destroy( &self->mutex );
597 * A Property holding binary data only copies the data if a serialiser
598 * function was supplied when you set the Property.
599 * \public \memberof mlt_property_s
600 * \author Zach <zachary.drew@gmail.com>
601 * \param self a property
602 * \param that another property
604 void mlt_property_pass( mlt_property self, mlt_property that )
606 mlt_property_clear( self );
608 self->types = that->types;
610 if ( self->types & mlt_prop_int64 )
611 self->prop_int64 = that->prop_int64;
612 else if ( self->types & mlt_prop_int )
613 self->prop_int = that->prop_int;
614 else if ( self->types & mlt_prop_double )
615 self->prop_double = that->prop_double;
616 else if ( self->types & mlt_prop_position )
617 self->prop_position = that->prop_position;
618 else if ( self->types & mlt_prop_string )
620 if ( that->prop_string != NULL )
621 self->prop_string = strdup( that->prop_string );
623 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
625 self->types = mlt_prop_string;
626 self->prop_string = self->serialiser( self->data, self->length );