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 pthread_mutex_lock( &self->mutex );
147 mlt_property_clear( self );
148 self->types = mlt_prop_int;
149 self->prop_int = value;
150 pthread_mutex_unlock( &self->mutex );
154 /** Set the property to a floating point value.
156 * \public \memberof mlt_property_s
157 * \param self a property
158 * \param value a double precision floating point value
162 int mlt_property_set_double( mlt_property self, double value )
164 pthread_mutex_lock( &self->mutex );
165 mlt_property_clear( self );
166 self->types = mlt_prop_double;
167 self->prop_double = value;
168 pthread_mutex_unlock( &self->mutex );
172 /** Set the property to a position value.
174 * Position is a relative time value in frame units.
175 * \public \memberof mlt_property_s
176 * \param self a property
177 * \param value a position value
181 int mlt_property_set_position( mlt_property self, mlt_position value )
183 pthread_mutex_lock( &self->mutex );
184 mlt_property_clear( self );
185 self->types = mlt_prop_position;
186 self->prop_position = value;
187 pthread_mutex_unlock( &self->mutex );
191 /** Set the property to a string value.
193 * This makes a copy of the string you supply so you do not need to track
194 * a new reference to it.
195 * \public \memberof mlt_property_s
196 * \param self a property
197 * \param value the string to copy to the property
198 * \return true if it failed
201 int mlt_property_set_string( mlt_property self, const char *value )
203 pthread_mutex_lock( &self->mutex );
204 if ( value != self->prop_string )
206 mlt_property_clear( self );
207 self->types = mlt_prop_string;
209 self->prop_string = strdup( value );
213 self->types = mlt_prop_string;
215 pthread_mutex_unlock( &self->mutex );
216 return self->prop_string == NULL;
219 /** Set the property to a 64-bit integer value.
221 * \public \memberof mlt_property_s
222 * \param self a property
223 * \param value a 64-bit integer
227 int mlt_property_set_int64( mlt_property self, int64_t value )
229 pthread_mutex_lock( &self->mutex );
230 mlt_property_clear( self );
231 self->types = mlt_prop_int64;
232 self->prop_int64 = value;
233 pthread_mutex_unlock( &self->mutex );
237 /** Set a property to an opaque binary value.
239 * This does not make a copy of the data. You can use a Properties object
240 * with its reference tracking and the destructor function to control
241 * the lifetime of the data. Otherwise, pass NULL for the destructor
242 * function and control the lifetime yourself.
243 * \public \memberof mlt_property_s
244 * \param self a property
245 * \param value an opaque pointer
246 * \param length the number of bytes pointed to by value (optional)
247 * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource)
248 * \param serialiser a function to use to convert this binary data to a string (optional)
252 int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
254 pthread_mutex_lock( &self->mutex );
255 if ( self->data == value )
256 self->destructor = NULL;
257 mlt_property_clear( self );
258 self->types = mlt_prop_data;
260 self->length = length;
261 self->destructor = destructor;
262 self->serialiser = serialiser;
263 pthread_mutex_unlock( &self->mutex );
267 /** Convert a base 10 or base 16 string to an integer.
269 * The string must begin with '0x' to be interpreted as hexadecimal.
270 * Otherwise, it is interpreted as base 10.
271 * If the string begins with '#' it is interpreted as a hexadecimal color value
272 * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
273 * always in the form RRGGBBAA where the alpha components are not optional.
274 * Applications and services should expect the binary color value in bytes to
275 * be in the following order: RGBA. This means they will have to cast the int
276 * to an unsigned int. This is especially important when they need to shift
277 * right to obtain RGB without alpha in order to make it do a logical instead
278 * of arithmetic shift.
280 * \private \memberof mlt_property_s
281 * \param value a string to convert
282 * \return the resultant integer
284 static inline int mlt_property_atoi( const char *value )
288 // Parse a hex color value as #RRGGBB or #AARRGGBB.
289 if ( value[0] == '#' )
291 unsigned int rgb = strtoul( value + 1, NULL, 16 );
292 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
293 return ( rgb << 8 ) | alpha;
295 // Do hex and decimal explicitly to avoid decimal value with leading zeros
296 // interpreted as octal.
297 else if ( value[0] == '0' && value[1] == 'x' )
299 return strtoul( value + 2, NULL, 16 );
303 return strtol( value, NULL, 10 );
307 /** Get the property as an integer.
309 * \public \memberof mlt_property_s
310 * \param self a property
311 * \return an integer value
314 int mlt_property_get_int( mlt_property self )
316 if ( self->types & mlt_prop_int )
317 return self->prop_int;
318 else if ( self->types & mlt_prop_double )
319 return ( int )self->prop_double;
320 else if ( self->types & mlt_prop_position )
321 return ( int )self->prop_position;
322 else if ( self->types & mlt_prop_int64 )
323 return ( int )self->prop_int64;
324 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
325 return mlt_property_atoi( self->prop_string );
329 /** Get the property as a floating point.
331 * \public \memberof mlt_property_s
332 * \param self a property
333 * \return a floating point value
336 double mlt_property_get_double( mlt_property self )
338 if ( self->types & mlt_prop_double )
339 return self->prop_double;
340 else if ( self->types & mlt_prop_int )
341 return ( double )self->prop_int;
342 else if ( self->types & mlt_prop_position )
343 return ( double )self->prop_position;
344 else if ( self->types & mlt_prop_int64 )
345 return ( double )self->prop_int64;
346 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
347 return atof( self->prop_string );
351 /** Get the property (with locale) as a floating point.
353 * \public \memberof mlt_property_s
354 * \param self a property
355 * \param locale the locale to use for this conversion
356 * \return a floating point value
359 double mlt_property_get_double_l( mlt_property self, locale_t locale )
361 if ( self->types & mlt_prop_double )
362 return self->prop_double;
363 else if ( self->types & mlt_prop_int )
364 return ( double )self->prop_int;
365 else if ( self->types & mlt_prop_position )
366 return ( double )self->prop_position;
367 else if ( self->types & mlt_prop_int64 )
368 return ( double )self->prop_int64;
369 #if defined(__GLIBC__) || defined(__DARWIN__)
370 else if ( locale && ( self->types & mlt_prop_string ) && self->prop_string )
371 return strtod_l( self->prop_string, NULL, locale );
373 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
374 return strtod( self->prop_string, NULL );
378 /** Get the property as a position.
380 * A position is an offset time in terms of frame units.
381 * \public \memberof mlt_property_s
382 * \param self a property
383 * \return the position in frames
386 mlt_position mlt_property_get_position( mlt_property self )
388 if ( self->types & mlt_prop_position )
389 return self->prop_position;
390 else if ( self->types & mlt_prop_int )
391 return ( mlt_position )self->prop_int;
392 else if ( self->types & mlt_prop_double )
393 return ( mlt_position )self->prop_double;
394 else if ( self->types & mlt_prop_int64 )
395 return ( mlt_position )self->prop_int64;
396 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
397 return ( mlt_position )atol( self->prop_string );
401 /** Convert a string to a 64-bit integer.
403 * If the string begins with '0x' it is interpreted as a hexadecimal value.
404 * \private \memberof mlt_property_s
405 * \param value a string
406 * \return a 64-bit integer
409 static inline int64_t mlt_property_atoll( const char *value )
413 else if ( value[0] == '0' && value[1] == 'x' )
414 return strtoll( value + 2, NULL, 16 );
416 return strtoll( value, NULL, 10 );
419 /** Get the property as a signed integer.
421 * \public \memberof mlt_property_s
422 * \param self a property
423 * \return a 64-bit integer
426 int64_t mlt_property_get_int64( mlt_property self )
428 if ( self->types & mlt_prop_int64 )
429 return self->prop_int64;
430 else if ( self->types & mlt_prop_int )
431 return ( int64_t )self->prop_int;
432 else if ( self->types & mlt_prop_double )
433 return ( int64_t )self->prop_double;
434 else if ( self->types & mlt_prop_position )
435 return ( int64_t )self->prop_position;
436 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
437 return mlt_property_atoll( self->prop_string );
441 /** Get the property as a string.
443 * The caller is not responsible for deallocating the returned string!
444 * The string is deallocated when the Property is closed.
445 * This tries its hardest to convert the property to string including using
446 * a serialization function for binary data, if supplied.
447 * \public \memberof mlt_property_s
448 * \param self a property
449 * \return a string representation of the property or NULL if failed
452 char *mlt_property_get_string( mlt_property self )
454 // Construct a string if need be
455 if ( ! ( self->types & mlt_prop_string ) )
457 pthread_mutex_lock( &self->mutex );
458 if ( self->types & mlt_prop_int )
460 self->types |= mlt_prop_string;
461 self->prop_string = malloc( 32 );
462 sprintf( self->prop_string, "%d", self->prop_int );
464 else if ( self->types & mlt_prop_double )
466 self->types |= mlt_prop_string;
467 self->prop_string = malloc( 32 );
468 sprintf( self->prop_string, "%f", self->prop_double );
470 else if ( self->types & mlt_prop_position )
472 self->types |= mlt_prop_string;
473 self->prop_string = malloc( 32 );
474 sprintf( self->prop_string, "%d", (int)self->prop_position );
476 else if ( self->types & mlt_prop_int64 )
478 self->types |= mlt_prop_string;
479 self->prop_string = malloc( 32 );
480 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
482 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
484 self->types |= mlt_prop_string;
485 self->prop_string = self->serialiser( self->data, self->length );
487 pthread_mutex_unlock( &self->mutex );
490 // Return the string (may be NULL)
491 return self->prop_string;
494 /** Get the property as a string (with locale).
496 * The caller is not responsible for deallocating the returned string!
497 * The string is deallocated when the Property is closed.
498 * This tries its hardest to convert the property to string including using
499 * a serialization function for binary data, if supplied.
500 * \public \memberof mlt_property_s
501 * \param self a property
502 * \param locale the locale to use for this conversion
503 * \return a string representation of the property or NULL if failed
506 char *mlt_property_get_string_l( mlt_property self, locale_t locale )
508 // Optimization for no locale
510 return mlt_property_get_string( self );
512 // Construct a string if need be
513 if ( ! ( self->types & mlt_prop_string ) )
515 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
516 // Save the current locale
517 #if defined(__DARWIN__)
518 const char *localename = querylocale( LC_NUMERIC, locale );
519 #elif defined(__GLIBC__)
520 const char *localename = locale->__names[ LC_NUMERIC ];
522 // TODO: not yet sure what to do on other platforms
523 const char *localename = "";
525 // Protect damaging the global locale from a temporary locale on another thread.
526 pthread_mutex_lock( &self->mutex );
528 // Get the current locale
529 char *orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
531 // Set the new locale
532 setlocale( LC_NUMERIC, localename );
534 if ( self->types & mlt_prop_int )
536 self->types |= mlt_prop_string;
537 self->prop_string = malloc( 32 );
538 sprintf( self->prop_string, "%d", self->prop_int );
540 else if ( self->types & mlt_prop_double )
542 self->types |= mlt_prop_string;
543 self->prop_string = malloc( 32 );
544 sprintf( self->prop_string, "%f", self->prop_double );
546 else if ( self->types & mlt_prop_position )
548 self->types |= mlt_prop_string;
549 self->prop_string = malloc( 32 );
550 sprintf( self->prop_string, "%d", (int)self->prop_position );
552 else if ( self->types & mlt_prop_int64 )
554 self->types |= mlt_prop_string;
555 self->prop_string = malloc( 32 );
556 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
558 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
560 self->types |= mlt_prop_string;
561 self->prop_string = self->serialiser( self->data, self->length );
563 // Restore the current locale
564 setlocale( LC_NUMERIC, orig_localename );
565 free( orig_localename );
566 pthread_mutex_unlock( &self->mutex );
569 // Return the string (may be NULL)
570 return self->prop_string;
573 /** Get the binary data from a property.
575 * This only works if you previously put binary data into the property.
576 * This does not return a copy of the data; it returns a pointer to it.
577 * If you supplied a destructor function when setting the binary data,
578 * the destructor is used when the Property is closed to free the memory.
579 * Therefore, only free the returned pointer if you did not supply a
580 * destructor function.
581 * \public \memberof mlt_property_s
582 * \param self a property
583 * \param[out] length the size of the binary object in bytes (optional)
584 * \return an opaque data pointer or NULL if not available
587 void *mlt_property_get_data( mlt_property self, int *length )
589 // Assign length if not NULL
590 if ( length != NULL )
591 *length = self->length;
593 // Return the data (note: there is no conversion here)
597 /** Destroy a property and free all related resources.
599 * \public \memberof mlt_property_s
600 * \param self a property
603 void mlt_property_close( mlt_property self )
605 mlt_property_clear( self );
606 pthread_mutex_destroy( &self->mutex );
612 * A Property holding binary data only copies the data if a serialiser
613 * function was supplied when you set the Property.
614 * \public \memberof mlt_property_s
615 * \author Zach <zachary.drew@gmail.com>
616 * \param self a property
617 * \param that another property
619 void mlt_property_pass( mlt_property self, mlt_property that )
621 pthread_mutex_lock( &self->mutex );
622 mlt_property_clear( self );
624 self->types = that->types;
626 if ( self->types & mlt_prop_int64 )
627 self->prop_int64 = that->prop_int64;
628 else if ( self->types & mlt_prop_int )
629 self->prop_int = that->prop_int;
630 else if ( self->types & mlt_prop_double )
631 self->prop_double = that->prop_double;
632 else if ( self->types & mlt_prop_position )
633 self->prop_position = that->prop_position;
634 if ( self->types & mlt_prop_string )
636 if ( that->prop_string != NULL )
637 self->prop_string = strdup( that->prop_string );
639 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
641 self->types = mlt_prop_string;
642 self->prop_string = self->serialiser( self->data, self->length );
644 pthread_mutex_unlock( &self->mutex );