3 * \brief Property class definition
6 * Copyright (C) 2003-2013 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
8 * \author Dan Dennedy <dan@dennedy.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "mlt_property.h"
31 #include "mlt_animation.h"
42 /** Bit pattern used internally to indicated representations available.
47 mlt_prop_none = 0, //!< not set
48 mlt_prop_int = 1, //!< set as an integer
49 mlt_prop_string = 2, //!< set as string or already converted to string
50 mlt_prop_position = 4,//!< set as a position
51 mlt_prop_double = 8, //!< set as a floating point
52 mlt_prop_data = 16, //!< set as opaque binary
53 mlt_prop_int64 = 32, //!< set as a 64-bit integer
54 mlt_prop_rect = 64 //!< set as a mlt_rect
58 /** \brief Property class
60 * A property is like a variant or dynamic type. They are used for many things
61 * in MLT, but in particular they are the parameter mechanism for the plugins.
66 /// Stores a bit pattern of types available for this property
67 mlt_property_type types;
69 /// Atomic type handling
71 mlt_position prop_position;
78 /// Generic type handling
81 mlt_destructor destructor;
82 mlt_serialiser serialiser;
84 pthread_mutex_t mutex;
85 mlt_animation animation;
88 /** Construct a property and initialize it
89 * \public \memberof mlt_property_s
92 mlt_property mlt_property_init( )
94 mlt_property self = calloc( 1, sizeof( *self ) );
96 pthread_mutex_init( &self->mutex, NULL );
100 /** Clear (0/null) a property.
102 * Frees up any associated resources in the process.
103 * \private \memberof mlt_property_s
104 * \param self a property
107 static inline void mlt_property_clear( mlt_property self )
109 // Special case data handling
110 if ( self->types & mlt_prop_data && self->destructor != NULL )
111 self->destructor( self->data );
113 // Special case string handling
114 if ( self->types & mlt_prop_string )
115 free( self->prop_string );
117 if ( self->animation )
118 mlt_animation_close( self->animation );
123 self->prop_position = 0;
124 self->prop_double = 0;
125 self->prop_int64 = 0;
126 self->prop_string = NULL;
129 self->destructor = NULL;
130 self->serialiser = NULL;
131 self->animation = NULL;
134 /** Set the property to an integer value.
136 * \public \memberof mlt_property_s
137 * \param self a property
138 * \param value an integer
142 int mlt_property_set_int( mlt_property self, int value )
144 pthread_mutex_lock( &self->mutex );
145 mlt_property_clear( self );
146 self->types = mlt_prop_int;
147 self->prop_int = value;
148 pthread_mutex_unlock( &self->mutex );
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 pthread_mutex_lock( &self->mutex );
163 mlt_property_clear( self );
164 self->types = mlt_prop_double;
165 self->prop_double = value;
166 pthread_mutex_unlock( &self->mutex );
170 /** Set the property to a position value.
172 * Position is a relative time value in frame units.
173 * \public \memberof mlt_property_s
174 * \param self a property
175 * \param value a position value
179 int mlt_property_set_position( mlt_property self, mlt_position value )
181 pthread_mutex_lock( &self->mutex );
182 mlt_property_clear( self );
183 self->types = mlt_prop_position;
184 self->prop_position = value;
185 pthread_mutex_unlock( &self->mutex );
189 /** Set the property to a string value.
191 * This makes a copy of the string you supply so you do not need to track
192 * a new reference to it.
193 * \public \memberof mlt_property_s
194 * \param self a property
195 * \param value the string to copy to the property
196 * \return true if it failed
199 int mlt_property_set_string( mlt_property self, const char *value )
201 pthread_mutex_lock( &self->mutex );
202 if ( value != self->prop_string )
204 mlt_property_clear( self );
205 self->types = mlt_prop_string;
207 self->prop_string = strdup( value );
211 self->types = mlt_prop_string;
213 pthread_mutex_unlock( &self->mutex );
214 return self->prop_string == NULL;
217 /** Set the property to a 64-bit integer value.
219 * \public \memberof mlt_property_s
220 * \param self a property
221 * \param value a 64-bit integer
225 int mlt_property_set_int64( mlt_property self, int64_t value )
227 pthread_mutex_lock( &self->mutex );
228 mlt_property_clear( self );
229 self->types = mlt_prop_int64;
230 self->prop_int64 = value;
231 pthread_mutex_unlock( &self->mutex );
235 /** Set a property to an opaque binary value.
237 * This does not make a copy of the data. You can use a Properties object
238 * with its reference tracking and the destructor function to control
239 * the lifetime of the data. Otherwise, pass NULL for the destructor
240 * function and control the lifetime yourself.
241 * \public \memberof mlt_property_s
242 * \param self a property
243 * \param value an opaque pointer
244 * \param length the number of bytes pointed to by value (optional)
245 * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource)
246 * \param serialiser a function to use to convert this binary data to a string (optional)
250 int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
252 pthread_mutex_lock( &self->mutex );
253 if ( self->data == value )
254 self->destructor = NULL;
255 mlt_property_clear( self );
256 self->types = mlt_prop_data;
258 self->length = length;
259 self->destructor = destructor;
260 self->serialiser = serialiser;
261 pthread_mutex_unlock( &self->mutex );
265 /** Parse a SMIL clock value.
267 * \private \memberof mlt_property_s
268 * \param self a property
269 * \param s the string to parse
270 * \param fps frames per second
271 * \param locale the locale to use for parsing a real number value
272 * \return position in frames
275 static int time_clock_to_frames( mlt_property self, const char *s, double fps, locale_t locale )
277 char *pos, *copy = strdup( s );
278 int hours = 0, minutes = 0;
282 pos = strrchr( s, ':' );
284 #if !defined(__GLIBC__) && !defined(__DARWIN__)
285 char *orig_localename = NULL;
288 // Protect damaging the global locale from a temporary locale on another thread.
289 pthread_mutex_lock( &self->mutex );
291 // Get the current locale
292 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
294 // Set the new locale
295 setlocale( LC_NUMERIC, locale );
300 #if defined(__GLIBC__) || defined(__DARWIN__)
302 seconds = strtod_l( pos + 1, NULL, locale );
305 seconds = strtod( pos + 1, NULL );
307 pos = strrchr( s, ':' );
309 minutes = atoi( pos + 1 );
318 #if defined(__GLIBC__) || defined(__DARWIN__)
320 seconds = strtod_l( s, NULL, locale );
323 seconds = strtod( s, NULL );
326 #if !defined(__GLIBC__) && !defined(__DARWIN__)
328 // Restore the current locale
329 setlocale( LC_NUMERIC, orig_localename );
330 free( orig_localename );
331 pthread_mutex_unlock( &self->mutex );
337 return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) );
340 /** Parse a SMPTE timecode string.
342 * \private \memberof mlt_property_s
343 * \param self a property
344 * \param s the string to parse
345 * \param fps frames per second
346 * \return position in frames
349 static int time_code_to_frames( mlt_property self, const char *s, double fps )
351 char *pos, *copy = strdup( s );
352 int hours = 0, minutes = 0, seconds = 0, frames;
355 pos = strrchr( s, ';' );
357 pos = strrchr( s, ':' );
359 frames = atoi( pos + 1 );
361 pos = strrchr( s, ':' );
363 seconds = atoi( pos + 1 );
365 pos = strrchr( s, ':' );
367 minutes = atoi( pos + 1 );
384 return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) + frames );
387 /** Convert a string to an integer.
389 * The string must begin with '0x' to be interpreted as hexadecimal.
390 * Otherwise, it is interpreted as base 10.
392 * If the string begins with '#' it is interpreted as a hexadecimal color value
393 * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
394 * always in the form RRGGBBAA where the alpha components are not optional.
395 * Applications and services should expect the binary color value in bytes to
396 * be in the following order: RGBA. This means they will have to cast the int
397 * to an unsigned int. This is especially important when they need to shift
398 * right to obtain RGB without alpha in order to make it do a logical instead
399 * of arithmetic shift.
401 * If the string contains a colon it is interpreted as a time value. If it also
402 * contains a period or comma character, the string is parsed as a clock value:
403 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
404 * \private \memberof mlt_property_s
405 * \param self a property
406 * \param fps frames per second, used when converting from time value
407 * \param locale the locale to use when converting from time clock value
408 * \return the resultant integer
410 static int mlt_property_atoi( mlt_property self, double fps, locale_t locale )
412 const char *value = self->prop_string;
414 // Parse a hex color value as #RRGGBB or #AARRGGBB.
415 if ( value[0] == '#' )
417 unsigned int rgb = strtoul( value + 1, NULL, 16 );
418 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
419 return ( rgb << 8 ) | alpha;
421 // Do hex and decimal explicitly to avoid decimal value with leading zeros
422 // interpreted as octal.
423 else if ( value[0] == '0' && value[1] == 'x' )
425 return strtoul( value + 2, NULL, 16 );
427 else if ( fps > 0 && strchr( value, ':' ) )
429 if ( strchr( value, '.' ) || strchr( value, ',' ) )
430 return time_clock_to_frames( self, value, fps, locale );
432 return time_code_to_frames( self, value, fps );
436 return strtol( value, NULL, 10 );
440 /** Get the property as an integer.
442 * \public \memberof mlt_property_s
443 * \param self a property
444 * \param fps frames per second, used when converting from time value
445 * \param locale the locale to use when converting from time clock value
446 * \return an integer value
449 int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
451 if ( self->types & mlt_prop_int )
452 return self->prop_int;
453 else if ( self->types & mlt_prop_double )
454 return ( int )self->prop_double;
455 else if ( self->types & mlt_prop_position )
456 return ( int )self->prop_position;
457 else if ( self->types & mlt_prop_int64 )
458 return ( int )self->prop_int64;
459 else if ( self->types & mlt_prop_rect && self->data )
460 return ( int ) ( (mlt_rect*) self->data )->x;
461 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
462 return mlt_property_atoi( self, fps, locale );
466 /** Convert a string to a floating point number.
468 * If the string contains a colon it is interpreted as a time value. If it also
469 * contains a period or comma character, the string is parsed as a clock value:
470 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
471 * If the numeric string ends with '%' then the value is divided by 100 to convert
473 * \private \memberof mlt_property_s
474 * \param self a property
475 * \param fps frames per second, used when converting from time value
476 * \param locale the locale to use when converting from time clock value
477 * \return the resultant real number
479 static double mlt_property_atof( mlt_property self, double fps, locale_t locale )
481 const char *value = self->prop_string;
483 if ( fps > 0 && strchr( value, ':' ) )
485 if ( strchr( value, '.' ) || strchr( value, ',' ) )
486 return time_clock_to_frames( self, value, fps, locale );
488 return time_code_to_frames( self, value, fps );
495 #if defined(__GLIBC__) || defined(__DARWIN__)
497 result = strtod_l( value, &end, locale );
500 char *orig_localename = NULL;
502 // Protect damaging the global locale from a temporary locale on another thread.
503 pthread_mutex_lock( &self->mutex );
505 // Get the current locale
506 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
508 // Set the new locale
509 setlocale( LC_NUMERIC, locale );
513 result = strtod( value, &end );
514 if ( end && end[0] == '%' )
517 #if !defined(__GLIBC__) && !defined(__DARWIN__)
519 // Restore the current locale
520 setlocale( LC_NUMERIC, orig_localename );
521 free( orig_localename );
522 pthread_mutex_unlock( &self->mutex );
530 /** Get the property as a floating point.
532 * \public \memberof mlt_property_s
533 * \param self a property
534 * \param fps frames per second, used when converting from time value
535 * \param locale the locale to use for this conversion
536 * \return a floating point value
539 double mlt_property_get_double( mlt_property self, double fps, locale_t locale )
541 if ( self->types & mlt_prop_double )
542 return self->prop_double;
543 else if ( self->types & mlt_prop_int )
544 return ( double )self->prop_int;
545 else if ( self->types & mlt_prop_position )
546 return ( double )self->prop_position;
547 else if ( self->types & mlt_prop_int64 )
548 return ( double )self->prop_int64;
549 else if ( self->types & mlt_prop_rect && self->data )
550 return ( (mlt_rect*) self->data )->x;
551 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
552 return mlt_property_atof( self, fps, locale );
556 /** Get the property as a position.
558 * A position is an offset time in terms of frame units.
559 * \public \memberof mlt_property_s
560 * \param self a property
561 * \param fps frames per second, used when converting from time value
562 * \param locale the locale to use when converting from time clock value
563 * \return the position in frames
566 mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t locale )
568 if ( self->types & mlt_prop_position )
569 return self->prop_position;
570 else if ( self->types & mlt_prop_int )
571 return ( mlt_position )self->prop_int;
572 else if ( self->types & mlt_prop_double )
573 return ( mlt_position )self->prop_double;
574 else if ( self->types & mlt_prop_int64 )
575 return ( mlt_position )self->prop_int64;
576 else if ( self->types & mlt_prop_rect && self->data )
577 return ( mlt_position ) ( (mlt_rect*) self->data )->x;
578 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
579 return ( mlt_position )mlt_property_atoi( self, fps, locale );
583 /** Convert a string to a 64-bit integer.
585 * If the string begins with '0x' it is interpreted as a hexadecimal value.
586 * \private \memberof mlt_property_s
587 * \param value a string
588 * \return a 64-bit integer
591 static inline int64_t mlt_property_atoll( const char *value )
595 else if ( value[0] == '0' && value[1] == 'x' )
596 return strtoll( value + 2, NULL, 16 );
598 return strtoll( value, NULL, 10 );
601 /** Get the property as a signed integer.
603 * \public \memberof mlt_property_s
604 * \param self a property
605 * \return a 64-bit integer
608 int64_t mlt_property_get_int64( mlt_property self )
610 if ( self->types & mlt_prop_int64 )
611 return self->prop_int64;
612 else if ( self->types & mlt_prop_int )
613 return ( int64_t )self->prop_int;
614 else if ( self->types & mlt_prop_double )
615 return ( int64_t )self->prop_double;
616 else if ( self->types & mlt_prop_position )
617 return ( int64_t )self->prop_position;
618 else if ( self->types & mlt_prop_rect && self->data )
619 return ( int64_t ) ( (mlt_rect*) self->data )->x;
620 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
621 return mlt_property_atoll( self->prop_string );
625 /** Get the property as a string.
627 * The caller is not responsible for deallocating the returned string!
628 * The string is deallocated when the Property is closed.
629 * This tries its hardest to convert the property to string including using
630 * a serialization function for binary data, if supplied.
631 * \public \memberof mlt_property_s
632 * \param self a property
633 * \return a string representation of the property or NULL if failed
636 char *mlt_property_get_string( mlt_property self )
638 // Construct a string if need be
639 if ( ! ( self->types & mlt_prop_string ) )
641 pthread_mutex_lock( &self->mutex );
642 if ( self->types & mlt_prop_int )
644 self->types |= mlt_prop_string;
645 self->prop_string = malloc( 32 );
646 sprintf( self->prop_string, "%d", self->prop_int );
648 else if ( self->types & mlt_prop_double )
650 self->types |= mlt_prop_string;
651 self->prop_string = malloc( 32 );
652 sprintf( self->prop_string, "%g", self->prop_double );
654 else if ( self->types & mlt_prop_position )
656 self->types |= mlt_prop_string;
657 self->prop_string = malloc( 32 );
658 sprintf( self->prop_string, "%d", (int)self->prop_position );
660 else if ( self->types & mlt_prop_int64 )
662 self->types |= mlt_prop_string;
663 self->prop_string = malloc( 32 );
664 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
666 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
668 self->types |= mlt_prop_string;
669 self->prop_string = self->serialiser( self->data, self->length );
671 pthread_mutex_unlock( &self->mutex );
674 // Return the string (may be NULL)
675 return self->prop_string;
678 /** Get the property as a string (with locale).
680 * The caller is not responsible for deallocating the returned string!
681 * The string is deallocated when the Property is closed.
682 * This tries its hardest to convert the property to string including using
683 * a serialization function for binary data, if supplied.
684 * \public \memberof mlt_property_s
685 * \param self a property
686 * \param locale the locale to use for this conversion
687 * \return a string representation of the property or NULL if failed
690 char *mlt_property_get_string_l( mlt_property self, locale_t locale )
692 // Optimization for no locale
694 return mlt_property_get_string( self );
696 // Construct a string if need be
697 if ( ! ( self->types & mlt_prop_string ) )
699 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
700 // Save the current locale
701 #if defined(__DARWIN__)
702 const char *localename = querylocale( LC_NUMERIC, locale );
703 #elif defined(__GLIBC__)
704 const char *localename = locale->__names[ LC_NUMERIC ];
706 const char *localename = locale;
708 // Protect damaging the global locale from a temporary locale on another thread.
709 pthread_mutex_lock( &self->mutex );
711 // Get the current locale
712 char *orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
714 // Set the new locale
715 setlocale( LC_NUMERIC, localename );
717 if ( self->types & mlt_prop_int )
719 self->types |= mlt_prop_string;
720 self->prop_string = malloc( 32 );
721 sprintf( self->prop_string, "%d", self->prop_int );
723 else if ( self->types & mlt_prop_double )
725 self->types |= mlt_prop_string;
726 self->prop_string = malloc( 32 );
727 sprintf( self->prop_string, "%g", self->prop_double );
729 else if ( self->types & mlt_prop_position )
731 self->types |= mlt_prop_string;
732 self->prop_string = malloc( 32 );
733 sprintf( self->prop_string, "%d", (int)self->prop_position );
735 else if ( self->types & mlt_prop_int64 )
737 self->types |= mlt_prop_string;
738 self->prop_string = malloc( 32 );
739 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
741 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
743 self->types |= mlt_prop_string;
744 self->prop_string = self->serialiser( self->data, self->length );
746 // Restore the current locale
747 setlocale( LC_NUMERIC, orig_localename );
748 free( orig_localename );
749 pthread_mutex_unlock( &self->mutex );
752 // Return the string (may be NULL)
753 return self->prop_string;
756 /** Get the binary data from a property.
758 * This only works if you previously put binary data into the property.
759 * This does not return a copy of the data; it returns a pointer to it.
760 * If you supplied a destructor function when setting the binary data,
761 * the destructor is used when the Property is closed to free the memory.
762 * Therefore, only free the returned pointer if you did not supply a
763 * destructor function.
764 * \public \memberof mlt_property_s
765 * \param self a property
766 * \param[out] length the size of the binary object in bytes (optional)
767 * \return an opaque data pointer or NULL if not available
770 void *mlt_property_get_data( mlt_property self, int *length )
772 // Assign length if not NULL
773 if ( length != NULL )
774 *length = self->length;
776 // Return the data (note: there is no conversion here)
780 /** Destroy a property and free all related resources.
782 * \public \memberof mlt_property_s
783 * \param self a property
786 void mlt_property_close( mlt_property self )
788 mlt_property_clear( self );
789 pthread_mutex_destroy( &self->mutex );
795 * A Property holding binary data only copies the data if a serialiser
796 * function was supplied when you set the Property.
797 * \public \memberof mlt_property_s
798 * \author Zach <zachary.drew@gmail.com>
799 * \param self a property
800 * \param that another property
802 void mlt_property_pass( mlt_property self, mlt_property that )
804 pthread_mutex_lock( &self->mutex );
805 mlt_property_clear( self );
807 self->types = that->types;
809 if ( self->types & mlt_prop_int64 )
810 self->prop_int64 = that->prop_int64;
811 else if ( self->types & mlt_prop_int )
812 self->prop_int = that->prop_int;
813 else if ( self->types & mlt_prop_double )
814 self->prop_double = that->prop_double;
815 else if ( self->types & mlt_prop_position )
816 self->prop_position = that->prop_position;
817 if ( self->types & mlt_prop_string )
819 if ( that->prop_string != NULL )
820 self->prop_string = strdup( that->prop_string );
822 else if ( that->types & mlt_prop_rect )
824 mlt_property_clear( self );
825 self->types = mlt_prop_rect | mlt_prop_data;
826 self->length = that->length;
827 self->data = calloc( 1, self->length );
828 memcpy( self->data, that->data, self->length );
829 self->destructor = free;
830 self->serialiser = that->serialiser;
832 else if ( self->types & mlt_prop_data && that->serialiser != NULL )
834 self->types = mlt_prop_string;
835 self->prop_string = that->serialiser( that->data, that->length );
837 pthread_mutex_unlock( &self->mutex );
840 /** Convert frame count to a SMPTE timecode string.
842 * \private \memberof mlt_property_s
843 * \param frames a frame count
844 * \param fps frames per second
845 * \param[out] s the string to write into - must have enough space to hold largest time string
848 static void time_smpte_from_frames( int frames, double fps, char *s )
850 int hours, mins, secs;
851 char frame_sep = ':';
853 if ( fps == 30000.0/1001.0 )
856 int i, max_frames = frames;
857 for ( i = 1800; i <= max_frames; i += 1800 )
867 hours = frames / ( fps * 3600 );
868 frames -= hours * ( fps * 3600 );
869 mins = frames / ( fps * 60 );
870 frames -= mins * ( fps * 60 );
872 frames -= secs * fps;
874 sprintf( s, "%02d:%02d:%02d%c%02d", hours, mins, secs, frame_sep, frames );
877 /** Convert frame count to a SMIL clock value string.
879 * \private \memberof mlt_property_s
880 * \param frames a frame count
881 * \param fps frames per second
882 * \param[out] s the string to write into - must have enough space to hold largest time string
885 static void time_clock_from_frames( int frames, double fps, char *s )
890 hours = frames / ( fps * 3600 );
891 frames -= hours * ( fps * 3600 );
892 mins = frames / ( fps * 60 );
893 frames -= mins * ( fps * 60 );
894 secs = (double) frames / fps;
896 sprintf( s, "%02d:%02d:%06.3f", hours, mins, secs );
899 /** Get the property as a time string.
901 * The time value can be either a SMPTE timecode or SMIL clock value.
902 * The caller is not responsible for deallocating the returned string!
903 * The string is deallocated when the property is closed.
904 * \public \memberof mlt_property_s
905 * \param self a property
906 * \param format the time format that you want
907 * \param fps frames per second
908 * \param locale the locale to use for this conversion
909 * \return a string representation of the property or NULL if failed
912 char *mlt_property_get_time( mlt_property self, mlt_time_format format, double fps, locale_t locale )
914 char *orig_localename = NULL;
915 const char *localename = "C";
917 // Optimization for mlt_time_frames
918 if ( format == mlt_time_frames )
919 return mlt_property_get_string_l( self, locale );
921 // Remove existing string
922 if ( self->prop_string )
923 mlt_property_set_int( self, mlt_property_get_int( self, fps, locale ) );
925 // Use the specified locale
928 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
929 // Save the current locale
930 #if defined(__DARWIN__)
931 localename = querylocale( LC_NUMERIC, locale );
932 #elif defined(__GLIBC__)
933 localename = locale->__names[ LC_NUMERIC ];
935 // TODO: not yet sure what to do on other platforms
937 // Protect damaging the global locale from a temporary locale on another thread.
938 pthread_mutex_lock( &self->mutex );
940 // Get the current locale
941 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
943 // Set the new locale
944 setlocale( LC_NUMERIC, localename );
948 // Make sure we have a lock before accessing self->types
949 pthread_mutex_lock( &self->mutex );
952 // Convert number to string
953 if ( self->types & mlt_prop_int )
955 self->types |= mlt_prop_string;
956 self->prop_string = malloc( 32 );
957 if ( format == mlt_time_clock )
958 time_clock_from_frames( self->prop_int, fps, self->prop_string );
960 time_smpte_from_frames( self->prop_int, fps, self->prop_string );
962 else if ( self->types & mlt_prop_position )
964 self->types |= mlt_prop_string;
965 self->prop_string = malloc( 32 );
966 if ( format == mlt_time_clock )
967 time_clock_from_frames( (int) self->prop_position, fps, self->prop_string );
969 time_smpte_from_frames( (int) self->prop_position, fps, self->prop_string );
971 else if ( self->types & mlt_prop_double )
973 self->types |= mlt_prop_string;
974 self->prop_string = malloc( 32 );
975 if ( format == mlt_time_clock )
976 time_clock_from_frames( self->prop_double, fps, self->prop_string );
978 time_smpte_from_frames( self->prop_double, fps, self->prop_string );
980 else if ( self->types & mlt_prop_int64 )
982 self->types |= mlt_prop_string;
983 self->prop_string = malloc( 32 );
984 if ( format == mlt_time_clock )
985 time_clock_from_frames( (int) self->prop_int64, fps, self->prop_string );
987 time_smpte_from_frames( (int) self->prop_int64, fps, self->prop_string );
990 // Restore the current locale
993 setlocale( LC_NUMERIC, orig_localename );
994 free( orig_localename );
995 pthread_mutex_unlock( &self->mutex );
999 // Make sure we have a lock before accessing self->types
1000 pthread_mutex_unlock( &self->mutex );
1003 // Return the string (may be NULL)
1004 return self->prop_string;
1007 /** Determine if the property holds a numeric or numeric string value.
1009 * \private \memberof mlt_property_s
1010 * \param self a property
1011 * \param locale the locale to use for string evaluation
1012 * \return true if it is numeric
1015 static int is_property_numeric( mlt_property self, locale_t locale )
1017 int result = ( self->types & mlt_prop_int ) ||
1018 ( self->types & mlt_prop_int64 ) ||
1019 ( self->types & mlt_prop_double ) ||
1020 ( self->types & mlt_prop_position ) ||
1021 ( self->types & mlt_prop_rect );
1023 // If not already numeric but string is numeric.
1024 if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
1029 #if defined(__GLIBC__) || defined(__DARWIN__)
1031 temp = strtod_l( self->prop_string, &p, locale );
1034 char *orig_localename = NULL;
1036 // Protect damaging the global locale from a temporary locale on another thread.
1037 pthread_mutex_lock( &self->mutex );
1039 // Get the current locale
1040 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
1042 // Set the new locale
1043 setlocale( LC_NUMERIC, locale );
1047 temp = strtod( self->prop_string, &p );
1049 #if !defined(__GLIBC__) && !defined(__DARWIN__)
1051 // Restore the current locale
1052 setlocale( LC_NUMERIC, orig_localename );
1053 free( orig_localename );
1054 pthread_mutex_unlock( &self->mutex );
1058 result = ( p != self->prop_string );
1063 /** A linear interpolation function for animation.
1065 * \private \memberof mlt_property_s
1068 static inline double linear_interpolate( double y1, double y2, double t )
1070 return y1 + ( y2 - y1 ) * t;
1073 /** A smooth spline interpolation for animation.
1075 * For non-closed curves, you need to also supply the tangent vector at the first and last control point.
1076 * This is commonly done: T(P[0]) = P[1] - P[0] and T(P[n]) = P[n] - P[n-1].
1077 * \private \memberof mlt_property_s
1080 static inline double catmull_rom_interpolate( double y0, double y1, double y2, double y3, double t )
1083 double a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
1084 double a1 = y0 - 2.5 * y1 + 2 * y2 - 0.5 * y3;
1085 double a2 = -0.5 * y0 + 0.5 * y2;
1087 return a0 * t * t2 + a1 * t2 + a2 * t + a3;
1090 /** Interpolate a new property value given a set of other properties.
1092 * \public \memberof mlt_property_s
1093 * \param self the property onto which to set the computed value
1094 * \param p an array of at least 1 value in p[1] if \p interp is discrete,
1095 * 2 values in p[1] and p[2] if \p interp is linear, or
1096 * 4 values in p[0] - p[3] if \p interp is smooth
1097 * \param progress a ratio in the range [0, 1] to indicate how far between p[1] and p[2]
1098 * \param fps the frame rate, which may be needed for converting a time string to frame units
1099 * \param locale the locale, which may be needed for converting a string to a real number
1100 * \param interp the interpolation method to use
1101 * \return true if there was an error
1104 int mlt_property_interpolate( mlt_property self, mlt_property p[],
1105 double progress, double fps, locale_t locale, mlt_keyframe_type interp )
1108 if ( interp != mlt_keyframe_discrete &&
1109 is_property_numeric( p[1], locale ) && is_property_numeric( p[2], locale ) )
1111 if ( self->types & mlt_prop_rect )
1113 mlt_rect value = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
1114 if ( interp == mlt_keyframe_linear )
1117 mlt_rect zero = {0, 0, 0, 0, 0};
1118 points[0] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
1121 points[1] = mlt_property_get_rect( p[2], locale );
1122 value.x = linear_interpolate( points[0].x, points[1].x, progress );
1123 value.y = linear_interpolate( points[0].y, points[1].y, progress );
1124 value.w = linear_interpolate( points[0].w, points[1].w, progress );
1125 value.h = linear_interpolate( points[0].h, points[1].h, progress );
1126 value.o = linear_interpolate( points[0].o, points[1].o, progress );
1133 else if ( interp == mlt_keyframe_smooth )
1136 mlt_rect zero = {0, 0, 0, 0, 0};
1137 points[1] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
1140 points[0] = p[0]? mlt_property_get_rect( p[0], locale ) : zero;
1141 points[2] = p[2]? mlt_property_get_rect( p[2], locale ) : zero;
1142 points[3] = p[3]? mlt_property_get_rect( p[3], locale ) : zero;
1143 value.x = catmull_rom_interpolate( points[0].x, points[1].x, points[2].x, points[3].x, progress );
1144 value.y = catmull_rom_interpolate( points[0].y, points[1].y, points[2].y, points[3].y, progress );
1145 value.w = catmull_rom_interpolate( points[0].w, points[1].w, points[2].w, points[3].w, progress );
1146 value.h = catmull_rom_interpolate( points[0].h, points[1].h, points[2].h, points[3].h, progress );
1147 value.o = catmull_rom_interpolate( points[0].o, points[1].o, points[2].o, points[3].o, progress );
1154 error = mlt_property_set_rect( self, value );
1159 if ( interp == mlt_keyframe_linear )
1162 points[0] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
1163 points[1] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
1164 value = p[2]? linear_interpolate( points[0], points[1], progress ) : points[0];
1166 else if ( interp == mlt_keyframe_smooth )
1169 points[0] = p[0]? mlt_property_get_double( p[0], fps, locale ) : 0;
1170 points[1] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
1171 points[2] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
1172 points[3] = p[3]? mlt_property_get_double( p[3], fps, locale ) : 0;
1173 value = p[2]? catmull_rom_interpolate( points[0], points[1], points[2], points[3], progress ) : points[1];
1175 error = mlt_property_set_double( self, value );
1180 mlt_property_pass( self, p[1] );
1185 /** Create a new animation or refresh an existing one.
1187 * \private \memberof mlt_property_s
1188 * \param self a property
1189 * \param fps the frame rate, which may be needed for converting a time string to frame units
1190 * \param locale the locale, which may be needed for converting a string to a real number
1191 * \param length the maximum number of frames when interpreting negative keyframe times,
1192 * <=0 if you don't care or need that
1195 static void refresh_animation( mlt_property self, double fps, locale_t locale, int length )
1197 if ( !self->animation )
1199 self->animation = mlt_animation_new();
1200 if ( self->prop_string )
1202 mlt_animation_parse( self->animation, self->prop_string, length, fps, locale );
1206 mlt_animation_set_length( self->animation, length );
1207 pthread_mutex_lock( &self->mutex );
1208 self->types |= mlt_prop_data;
1209 self->data = self->animation;
1210 self->serialiser = (mlt_serialiser) mlt_animation_serialize;
1211 pthread_mutex_unlock( &self->mutex );
1214 else if ( self->prop_string )
1216 mlt_animation_refresh( self->animation, self->prop_string, length );
1220 /** Get the real number at a frame position.
1222 * \public \memberof mlt_property_s
1223 * \param self a property
1224 * \param fps the frame rate, which may be needed for converting a time string to frame units
1225 * \param locale the locale, which may be needed for converting a string to a real number
1226 * \param position the frame number
1227 * \param length the maximum number of frames when interpreting negative keyframe times,
1228 * <=0 if you don't care or need that
1229 * \return the real number
1232 double mlt_property_anim_get_double( mlt_property self, double fps, locale_t locale, int position, int length )
1234 pthread_mutex_lock( &self->mutex );
1236 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1238 struct mlt_animation_item_s item;
1239 item.property = mlt_property_init();
1241 refresh_animation( self, fps, locale, length );
1242 mlt_animation_get_item( self->animation, &item, position );
1243 result = mlt_property_get_double( item.property, fps, locale );
1245 mlt_property_close( item.property );
1249 result = mlt_property_get_double( self, fps, locale );
1251 pthread_mutex_unlock( &self->mutex );
1255 /** Get the property as an integer number at a frame position.
1257 * \public \memberof mlt_property_s
1258 * \param self a property
1259 * \param fps the frame rate, which may be needed for converting a time string to frame units
1260 * \param locale the locale, which may be needed for converting a string to a real number
1261 * \param position the frame number
1262 * \param length the maximum number of frames when interpreting negative keyframe times,
1263 * <=0 if you don't care or need that
1264 * \return an integer value
1267 int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, int position, int length )
1269 pthread_mutex_lock( &self->mutex );
1271 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1273 struct mlt_animation_item_s item;
1274 item.property = mlt_property_init();
1276 refresh_animation( self, fps, locale, length );
1277 mlt_animation_get_item( self->animation, &item, position );
1278 result = mlt_property_get_int( item.property, fps, locale );
1280 mlt_property_close( item.property );
1284 result = mlt_property_get_int( self, fps, locale );
1286 pthread_mutex_unlock( &self->mutex );
1290 /** Get the string at certain a frame position.
1292 * \public \memberof mlt_property_s
1293 * \param self a property
1294 * \param fps the frame rate, which may be needed for converting a time string to frame units
1295 * \param locale the locale, which may be needed for converting a string to a real number
1296 * \param position the frame number
1297 * \param length the maximum number of frames when interpreting negative keyframe times,
1298 * <=0 if you don't care or need that
1299 * \return the string representation of the property or NULL if failed
1302 char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t locale, int position, int length )
1304 pthread_mutex_lock( &self->mutex );
1306 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1308 struct mlt_animation_item_s item;
1309 item.property = mlt_property_init();
1311 if ( !self->animation )
1312 refresh_animation( self, fps, locale, length );
1313 mlt_animation_get_item( self->animation, &item, position );
1315 if ( self->prop_string )
1316 free( self->prop_string );
1317 self->prop_string = mlt_property_get_string_l( item.property, locale );
1318 if ( self->prop_string )
1319 self->prop_string = strdup( self->prop_string );
1320 self->types |= mlt_prop_string;
1322 result = self->prop_string;
1323 mlt_property_close( item.property );
1327 result = mlt_property_get_string_l( self, locale );
1329 pthread_mutex_unlock( &self->mutex );
1333 /** Set a property animation keyframe to a real number.
1335 * \public \memberof mlt_property_s
1336 * \param self a property
1337 * \param value a double precision floating point value
1338 * \param fps the frame rate, which may be needed for converting a time string to frame units
1339 * \param locale the locale, which may be needed for converting a string to a real number
1340 * \param position the frame number
1341 * \param length the maximum number of frames when interpreting negative keyframe times,
1342 * <=0 if you don't care or need that
1343 * \param keyframe_type the interpolation method for this keyframe
1344 * \return false if successful, true to indicate error
1347 int mlt_property_anim_set_double( mlt_property self, double value, double fps, locale_t locale,
1348 int position, int length, mlt_keyframe_type keyframe_type )
1351 struct mlt_animation_item_s item;
1353 item.property = mlt_property_init();
1354 item.frame = position;
1355 item.keyframe_type = keyframe_type;
1356 mlt_property_set_double( item.property, value );
1358 refresh_animation( self, fps, locale, length );
1359 result = mlt_animation_insert( self->animation, &item );
1360 mlt_animation_interpolate( self->animation );
1361 mlt_property_close( item.property );
1366 /** Set a property animation keyframe to an integer value.
1368 * \public \memberof mlt_property_s
1369 * \param self a property
1370 * \param value an integer
1371 * \param fps the frame rate, which may be needed for converting a time string to frame units
1372 * \param locale the locale, which may be needed for converting a string to a real number
1373 * \param position the frame number
1374 * \param length the maximum number of frames when interpreting negative keyframe times,
1375 * <=0 if you don't care or need that
1376 * \param keyframe_type the interpolation method for this keyframe
1377 * \return false if successful, true to indicate error
1380 int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_t locale,
1381 int position, int length, mlt_keyframe_type keyframe_type )
1384 struct mlt_animation_item_s item;
1386 item.property = mlt_property_init();
1387 item.frame = position;
1388 item.keyframe_type = keyframe_type;
1389 mlt_property_set_int( item.property, value );
1391 refresh_animation( self, fps, locale, length );
1392 result = mlt_animation_insert( self->animation, &item );
1393 mlt_animation_interpolate( self->animation );
1394 mlt_property_close( item.property );
1399 /** Set a property animation keyframe to a string.
1401 * Strings only support discrete animation. Do not use this to set a property's
1402 * animation string that contains a semicolon-delimited set of values; use
1403 * mlt_property_set() for that.
1404 * \public \memberof mlt_property_s
1405 * \param self a property
1406 * \param value a string
1407 * \param fps the frame rate, which may be needed for converting a time string to frame units
1408 * \param locale the locale, which may be needed for converting a string to a real number
1409 * \param position the frame number
1410 * \param length the maximum number of frames when interpreting negative keyframe times,
1411 * <=0 if you don't care or need that
1412 * \return false if successful, true to indicate error
1415 int mlt_property_anim_set_string( mlt_property self, const char *value, double fps, locale_t locale, int position, int length )
1418 struct mlt_animation_item_s item;
1420 item.property = mlt_property_init();
1421 item.frame = position;
1422 item.keyframe_type = mlt_keyframe_discrete;
1423 mlt_property_set_string( item.property, value );
1425 refresh_animation( self, fps, locale, length );
1426 result = mlt_animation_insert( self->animation, &item );
1427 mlt_animation_interpolate( self->animation );
1428 mlt_property_close( item.property );
1433 /** Get an object's animation object.
1435 * You might need to call another mlt_property_anim_ function to actually construct
1436 * the animation, as this is a simple accessor function.
1437 * \public \memberof mlt_property_s
1438 * \param self a property
1439 * \return the animation object or NULL if there is no animation
1442 mlt_animation mlt_property_get_animation( mlt_property self )
1444 return self->animation;
1447 /** Convert a rectangle value into a string.
1449 * Unlike the deprecated mlt_geometry API, the canonical form of a mlt_rect
1450 * is a space delimited "x y w h o" even though many kinds of field delimiters
1451 * may be used to convert a string to a rectangle.
1452 * \private \memberof mlt_property_s
1453 * \param rect the rectangle to convert
1454 * \param length not used
1455 * \return the string representation of a rectangle
1458 static char* serialise_mlt_rect( mlt_rect *rect, int length )
1460 char* result = calloc( 1, 100 );
1461 if ( rect->x != DBL_MIN )
1462 sprintf( result + strlen( result ), "%g", rect->x );
1463 if ( rect->y != DBL_MIN )
1464 sprintf( result + strlen( result ), " %g", rect->y );
1465 if ( rect->w != DBL_MIN )
1466 sprintf( result + strlen( result ), " %g", rect->w );
1467 if ( rect->h != DBL_MIN )
1468 sprintf( result + strlen( result ), " %g", rect->h );
1469 if ( rect->o != DBL_MIN )
1470 sprintf( result + strlen( result ), " %g", rect->o );
1474 /** Set a property to a mlt_rect rectangle.
1476 * \public \memberof mlt_property_s
1477 * \param self a property
1478 * \param value a rectangle
1482 int mlt_property_set_rect( mlt_property self, mlt_rect value )
1484 pthread_mutex_lock( &self->mutex );
1485 mlt_property_clear( self );
1486 self->types = mlt_prop_rect | mlt_prop_data;
1487 self->length = sizeof(value);
1488 self->data = calloc( 1, self->length );
1489 memcpy( self->data, &value, self->length );
1490 self->destructor = free;
1491 self->serialiser = (mlt_serialiser) serialise_mlt_rect;
1492 pthread_mutex_unlock( &self->mutex );
1496 /** Get the property as a rectangle.
1498 * You can use any non-numeric character(s) as a field delimiter.
1499 * If the number has a '%' immediately following it, the number is divided by
1500 * 100 to convert it into a real number.
1501 * \public \memberof mlt_property_s
1502 * \param self a property
1503 * \param locale the locale to use for when converting from a string
1504 * \return a rectangle value
1507 mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale )
1509 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
1510 if ( self->types & mlt_prop_rect )
1511 rect = *( (mlt_rect*) self->data );
1512 else if ( self->types & mlt_prop_double )
1513 rect.x = self->prop_double;
1514 else if ( self->types & mlt_prop_int )
1515 rect.x = ( double )self->prop_int;
1516 else if ( self->types & mlt_prop_position )
1517 rect.x = ( double )self->prop_position;
1518 else if ( self->types & mlt_prop_int64 )
1519 rect.x = ( double )self->prop_int64;
1520 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
1522 char *value = self->prop_string;
1526 #if !defined(__GLIBC__) && !defined(__DARWIN__)
1527 char *orig_localename = NULL;
1529 // Protect damaging the global locale from a temporary locale on another thread.
1530 pthread_mutex_lock( &self->mutex );
1532 // Get the current locale
1533 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
1535 // Set the new locale
1536 setlocale( LC_NUMERIC, locale );
1543 #if defined(__GLIBC__) || defined(__DARWIN__)
1545 temp = strtod_l( value, &p, locale );
1548 temp = strtod( value, &p );
1557 // Chomp the delimiter.
1560 // Assign the value to appropriate field.
1563 case 0: rect.x = temp; break;
1564 case 1: rect.y = temp; break;
1565 case 2: rect.w = temp; break;
1566 case 3: rect.h = temp; break;
1567 case 4: rect.o = temp; break;
1578 #if !defined(__GLIBC__) && !defined(__DARWIN__)
1580 // Restore the current locale
1581 setlocale( LC_NUMERIC, orig_localename );
1582 free( orig_localename );
1583 pthread_mutex_unlock( &self->mutex );
1590 /** Set a property animation keyframe to a rectangle.
1592 * \public \memberof mlt_property_s
1593 * \param self a property
1594 * \param value a rectangle
1595 * \param fps the frame rate, which may be needed for converting a time string to frame units
1596 * \param locale the locale, which may be needed for converting a string to a real number
1597 * \param position the frame number
1598 * \param length the maximum number of frames when interpreting negative keyframe times,
1599 * <=0 if you don't care or need that
1600 * \param keyframe_type the interpolation method for this keyframe
1601 * \return false if successful, true to indicate error
1604 int mlt_property_anim_set_rect( mlt_property self, mlt_rect value, double fps, locale_t locale,
1605 int position, int length, mlt_keyframe_type keyframe_type )
1608 struct mlt_animation_item_s item;
1610 item.property = mlt_property_init();
1611 item.frame = position;
1612 item.keyframe_type = keyframe_type;
1613 mlt_property_set_rect( item.property, value );
1615 refresh_animation( self, fps, locale, length );
1616 result = mlt_animation_insert( self->animation, &item );
1617 mlt_animation_interpolate( self->animation );
1618 mlt_property_close( item.property );
1623 /** Get a rectangle at a frame position.
1625 * \public \memberof mlt_property_s
1626 * \param self a property
1627 * \param fps the frame rate, which may be needed for converting a time string to frame units
1628 * \param locale the locale, which may be needed for converting a string to a real number
1629 * \param position the frame number
1630 * \param length the maximum number of frames when interpreting negative keyframe times,
1631 * <=0 if you don't care or need that
1632 * \return the rectangle
1635 mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t locale, int position, int length )
1637 pthread_mutex_lock( &self->mutex );
1639 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1641 struct mlt_animation_item_s item;
1642 item.property = mlt_property_init();
1643 item.property->types = mlt_prop_rect;
1645 refresh_animation( self, fps, locale, length );
1646 mlt_animation_get_item( self->animation, &item, position );
1647 result = mlt_property_get_rect( item.property, locale );
1649 mlt_property_close( item.property );
1653 result = mlt_property_get_rect( self, locale );
1655 pthread_mutex_unlock( &self->mutex );