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 /** Parse a SMIL clock value.
269 * \private \memberof mlt_property_s
270 * \param s the string to parse
271 * \param fps frames per second
272 * \param locale the locale to use for parsing a real number value
273 * \return position in frames
276 static int time_clock_to_frames( const char *s, double fps, locale_t locale )
278 char *pos, *copy = strdup( s );
279 int hours = 0, minutes = 0;
283 pos = strrchr( s, ':' );
285 #if defined(__GLIBC__) || defined(__DARWIN__)
287 seconds = strtod_l( pos + 1, NULL, locale );
290 seconds = strtod( pos + 1, NULL );
292 pos = strrchr( s, ':' );
294 minutes = atoi( pos + 1 );
303 #if defined(__GLIBC__) || defined(__DARWIN__)
305 seconds = strtod_l( s, NULL, locale );
308 seconds = strtod( s, NULL );
312 return fps * ( (hours * 3600) + (minutes * 60) + seconds ) + 0.5;
315 /** Parse a SMPTE timecode string.
317 * \private \memberof mlt_property_s
318 * \param s the string to parse
319 * \param fps frames per second
320 * \return position in frames
323 static int time_code_to_frames( const char *s, double fps )
325 char *pos, *copy = strdup( s );
326 int hours = 0, minutes = 0, seconds = 0, frames;
329 pos = strrchr( s, ';' );
331 pos = strrchr( s, ':' );
333 frames = atoi( pos + 1 );
335 pos = strrchr( s, ':' );
337 seconds = atoi( pos + 1 );
339 pos = strrchr( s, ':' );
341 minutes = atoi( pos + 1 );
358 return frames + ( fps * ( (hours * 3600) + (minutes * 60) + seconds ) + 0.5 );
361 /** Convert a string to an integer.
363 * The string must begin with '0x' to be interpreted as hexadecimal.
364 * Otherwise, it is interpreted as base 10.
366 * If the string begins with '#' it is interpreted as a hexadecimal color value
367 * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
368 * always in the form RRGGBBAA where the alpha components are not optional.
369 * Applications and services should expect the binary color value in bytes to
370 * be in the following order: RGBA. This means they will have to cast the int
371 * to an unsigned int. This is especially important when they need to shift
372 * right to obtain RGB without alpha in order to make it do a logical instead
373 * of arithmetic shift.
375 * If the string contains a colon it is interpreted as a time value. If it also
376 * contains a period or comma character, the string is parsed as a clock value:
377 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
378 * \private \memberof mlt_property_s
379 * \param value a string to convert
380 * \param fps frames per second, used when converting from time value
381 * \param locale the locale to use when converting from time clock value
382 * \return the resultant integer
384 static int mlt_property_atoi( const char *value, double fps, locale_t locale )
386 // Parse a hex color value as #RRGGBB or #AARRGGBB.
387 if ( value[0] == '#' )
389 unsigned int rgb = strtoul( value + 1, NULL, 16 );
390 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
391 return ( rgb << 8 ) | alpha;
393 // Do hex and decimal explicitly to avoid decimal value with leading zeros
394 // interpreted as octal.
395 else if ( value[0] == '0' && value[1] == 'x' )
397 return strtoul( value + 2, NULL, 16 );
399 else if ( fps > 0 && strchr( value, ':' ) )
401 if ( strchr( value, '.' ) || strchr( value, ',' ) )
402 return time_clock_to_frames( value, fps, locale );
404 return time_code_to_frames( value, fps );
408 return strtol( value, NULL, 10 );
412 /** Get the property as an integer.
414 * \public \memberof mlt_property_s
415 * \param self a property
416 * \param fps frames per second, used when converting from time value
417 * \param locale the locale to use when converting from time clock value
418 * \return an integer value
421 int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
423 if ( self->types & mlt_prop_int )
424 return self->prop_int;
425 else if ( self->types & mlt_prop_double )
426 return ( int )self->prop_double;
427 else if ( self->types & mlt_prop_position )
428 return ( int )self->prop_position;
429 else if ( self->types & mlt_prop_int64 )
430 return ( int )self->prop_int64;
431 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
432 return mlt_property_atoi( self->prop_string, fps, locale );
436 /** Convert a string to a floating point number.
438 * If the string contains a colon it is interpreted as a time value. If it also
439 * contains a period or comma character, the string is parsed as a clock value:
440 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
441 * \private \memberof mlt_property_s
442 * \param value the string to convert
443 * \param fps frames per second, used when converting from time value
444 * \param locale the locale to use when converting from time clock value
445 * \return the resultant real number
447 static double mlt_property_atof( const char *value, double fps, locale_t locale )
449 if ( fps > 0 && strchr( value, ':' ) )
451 if ( strchr( value, '.' ) || strchr( value, ',' ) )
452 return time_clock_to_frames( value, fps, locale );
454 return time_code_to_frames( value, fps );
458 #if defined(__GLIBC__) || defined(__DARWIN__)
460 return strtod_l( value, NULL, locale );
462 return strtod( value, NULL );
466 /** Get the property as a floating point.
468 * \public \memberof mlt_property_s
469 * \param self a property
470 * \param fps frames per second, used when converting from time value
471 * \param locale the locale to use for this conversion
472 * \return a floating point value
475 double mlt_property_get_double( mlt_property self, double fps, locale_t locale )
477 if ( self->types & mlt_prop_double )
478 return self->prop_double;
479 else if ( self->types & mlt_prop_int )
480 return ( double )self->prop_int;
481 else if ( self->types & mlt_prop_position )
482 return ( double )self->prop_position;
483 else if ( self->types & mlt_prop_int64 )
484 return ( double )self->prop_int64;
485 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
486 return mlt_property_atof( self->prop_string, fps, locale );
490 /** Get the property as a position.
492 * A position is an offset time in terms of frame units.
493 * \public \memberof mlt_property_s
494 * \param self a property
495 * \param fps frames per second, used when converting from time value
496 * \param locale the locale to use when converting from time clock value
497 * \return the position in frames
500 mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t locale )
502 if ( self->types & mlt_prop_position )
503 return self->prop_position;
504 else if ( self->types & mlt_prop_int )
505 return ( mlt_position )self->prop_int;
506 else if ( self->types & mlt_prop_double )
507 return ( mlt_position )self->prop_double;
508 else if ( self->types & mlt_prop_int64 )
509 return ( mlt_position )self->prop_int64;
510 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
511 return ( mlt_position )mlt_property_atoi( self->prop_string, fps, locale );
515 /** Convert a string to a 64-bit integer.
517 * If the string begins with '0x' it is interpreted as a hexadecimal value.
518 * \private \memberof mlt_property_s
519 * \param value a string
520 * \return a 64-bit integer
523 static inline int64_t mlt_property_atoll( const char *value )
527 else if ( value[0] == '0' && value[1] == 'x' )
528 return strtoll( value + 2, NULL, 16 );
530 return strtoll( value, NULL, 10 );
533 /** Get the property as a signed integer.
535 * \public \memberof mlt_property_s
536 * \param self a property
537 * \return a 64-bit integer
540 int64_t mlt_property_get_int64( mlt_property self )
542 if ( self->types & mlt_prop_int64 )
543 return self->prop_int64;
544 else if ( self->types & mlt_prop_int )
545 return ( int64_t )self->prop_int;
546 else if ( self->types & mlt_prop_double )
547 return ( int64_t )self->prop_double;
548 else if ( self->types & mlt_prop_position )
549 return ( int64_t )self->prop_position;
550 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
551 return mlt_property_atoll( self->prop_string );
555 /** Get the property as a string.
557 * The caller is not responsible for deallocating the returned string!
558 * The string is deallocated when the Property is closed.
559 * This tries its hardest to convert the property to string including using
560 * a serialization function for binary data, if supplied.
561 * \public \memberof mlt_property_s
562 * \param self a property
563 * \return a string representation of the property or NULL if failed
566 char *mlt_property_get_string( mlt_property self )
568 // Construct a string if need be
569 if ( ! ( self->types & mlt_prop_string ) )
571 pthread_mutex_lock( &self->mutex );
572 if ( self->types & mlt_prop_int )
574 self->types |= mlt_prop_string;
575 self->prop_string = malloc( 32 );
576 sprintf( self->prop_string, "%d", self->prop_int );
578 else if ( self->types & mlt_prop_double )
580 self->types |= mlt_prop_string;
581 self->prop_string = malloc( 32 );
582 sprintf( self->prop_string, "%f", self->prop_double );
584 else if ( self->types & mlt_prop_position )
586 self->types |= mlt_prop_string;
587 self->prop_string = malloc( 32 );
588 sprintf( self->prop_string, "%d", (int)self->prop_position );
590 else if ( self->types & mlt_prop_int64 )
592 self->types |= mlt_prop_string;
593 self->prop_string = malloc( 32 );
594 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
596 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
598 self->types |= mlt_prop_string;
599 self->prop_string = self->serialiser( self->data, self->length );
601 pthread_mutex_unlock( &self->mutex );
604 // Return the string (may be NULL)
605 return self->prop_string;
608 /** Get the property as a string (with locale).
610 * The caller is not responsible for deallocating the returned string!
611 * The string is deallocated when the Property is closed.
612 * This tries its hardest to convert the property to string including using
613 * a serialization function for binary data, if supplied.
614 * \public \memberof mlt_property_s
615 * \param self a property
616 * \param locale the locale to use for this conversion
617 * \return a string representation of the property or NULL if failed
620 char *mlt_property_get_string_l( mlt_property self, locale_t locale )
622 // Optimization for no locale
624 return mlt_property_get_string( self );
626 // Construct a string if need be
627 if ( ! ( self->types & mlt_prop_string ) )
629 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
630 // Save the current locale
631 #if defined(__DARWIN__)
632 const char *localename = querylocale( LC_NUMERIC, locale );
633 #elif defined(__GLIBC__)
634 const char *localename = locale->__names[ LC_NUMERIC ];
636 // TODO: not yet sure what to do on other platforms
637 const char *localename = "";
639 // Protect damaging the global locale from a temporary locale on another thread.
640 pthread_mutex_lock( &self->mutex );
642 // Get the current locale
643 char *orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
645 // Set the new locale
646 setlocale( LC_NUMERIC, localename );
648 if ( self->types & mlt_prop_int )
650 self->types |= mlt_prop_string;
651 self->prop_string = malloc( 32 );
652 sprintf( self->prop_string, "%d", self->prop_int );
654 else if ( self->types & mlt_prop_double )
656 self->types |= mlt_prop_string;
657 self->prop_string = malloc( 32 );
658 sprintf( self->prop_string, "%f", self->prop_double );
660 else if ( self->types & mlt_prop_position )
662 self->types |= mlt_prop_string;
663 self->prop_string = malloc( 32 );
664 sprintf( self->prop_string, "%d", (int)self->prop_position );
666 else if ( self->types & mlt_prop_int64 )
668 self->types |= mlt_prop_string;
669 self->prop_string = malloc( 32 );
670 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
672 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
674 self->types |= mlt_prop_string;
675 self->prop_string = self->serialiser( self->data, self->length );
677 // Restore the current locale
678 setlocale( LC_NUMERIC, orig_localename );
679 free( orig_localename );
680 pthread_mutex_unlock( &self->mutex );
683 // Return the string (may be NULL)
684 return self->prop_string;
687 /** Get the binary data from a property.
689 * This only works if you previously put binary data into the property.
690 * This does not return a copy of the data; it returns a pointer to it.
691 * If you supplied a destructor function when setting the binary data,
692 * the destructor is used when the Property is closed to free the memory.
693 * Therefore, only free the returned pointer if you did not supply a
694 * destructor function.
695 * \public \memberof mlt_property_s
696 * \param self a property
697 * \param[out] length the size of the binary object in bytes (optional)
698 * \return an opaque data pointer or NULL if not available
701 void *mlt_property_get_data( mlt_property self, int *length )
703 // Assign length if not NULL
704 if ( length != NULL )
705 *length = self->length;
707 // Return the data (note: there is no conversion here)
711 /** Destroy a property and free all related resources.
713 * \public \memberof mlt_property_s
714 * \param self a property
717 void mlt_property_close( mlt_property self )
719 mlt_property_clear( self );
720 pthread_mutex_destroy( &self->mutex );
726 * A Property holding binary data only copies the data if a serialiser
727 * function was supplied when you set the Property.
728 * \public \memberof mlt_property_s
729 * \author Zach <zachary.drew@gmail.com>
730 * \param self a property
731 * \param that another property
733 void mlt_property_pass( mlt_property self, mlt_property that )
735 pthread_mutex_lock( &self->mutex );
736 mlt_property_clear( self );
738 self->types = that->types;
740 if ( self->types & mlt_prop_int64 )
741 self->prop_int64 = that->prop_int64;
742 else if ( self->types & mlt_prop_int )
743 self->prop_int = that->prop_int;
744 else if ( self->types & mlt_prop_double )
745 self->prop_double = that->prop_double;
746 else if ( self->types & mlt_prop_position )
747 self->prop_position = that->prop_position;
748 if ( self->types & mlt_prop_string )
750 if ( that->prop_string != NULL )
751 self->prop_string = strdup( that->prop_string );
753 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
755 self->types = mlt_prop_string;
756 self->prop_string = self->serialiser( self->data, self->length );
758 pthread_mutex_unlock( &self->mutex );
761 /** Convert frame count to a SMPTE timecode string.
763 * \private \memberof mlt_property_s
764 * \param frames a frame count
765 * \param fps frames per second
766 * \param[out] s the string to write into - must have enough space to hold largest time string
769 static void time_smpte_from_frames( int frames, double fps, char *s )
771 int hours, mins, secs;
772 char frame_sep = ':';
774 if ( fps == 30000.0/1001.0 )
777 int i, max_frames = frames;
778 for ( i = 1800; i <= max_frames; i += 1800 )
788 hours = frames / ( fps * 3600 );
789 frames -= hours * ( fps * 3600 );
790 mins = frames / ( fps * 60 );
791 frames -= mins * ( fps * 60 );
793 frames -= secs * fps;
795 sprintf( s, "%02d:%02d:%02d%c%02d", hours, mins, secs, frame_sep, frames );
798 /** Convert frame count to a SMIL clock value string.
800 * \private \memberof mlt_property_s
801 * \param frames a frame count
802 * \param fps frames per second
803 * \param[out] s the string to write into - must have enough space to hold largest time string
806 static void time_clock_from_frames( int frames, double fps, char *s )
811 hours = frames / ( fps * 3600 );
812 frames -= hours * ( fps * 3600 );
813 mins = frames / ( fps * 60 );
814 frames -= mins * ( fps * 60 );
815 secs = (double) frames / fps;
817 sprintf( s, "%02d:%02d:%06.3f", hours, mins, secs );
820 /** Get the property as a time string.
822 * The time value can be either a SMPTE timecode or SMIL clock value.
823 * The caller is not responsible for deallocating the returned string!
824 * The string is deallocated when the property is closed.
825 * \public \memberof mlt_property_s
826 * \param self a property
827 * \param format the time format that you want
828 * \param fps frames per second
829 * \param locale the locale to use for this conversion
830 * \return a string representation of the property or NULL if failed
833 char *mlt_property_get_time( mlt_property self, mlt_time_format format, double fps, locale_t locale )
835 char *orig_localename = NULL;
836 const char *localename = "";
838 // Optimization for mlt_time_frames
839 if ( format == mlt_time_frames )
840 return mlt_property_get_string_l( self, locale );
842 // Remove existing string
843 if ( self->prop_string )
844 mlt_property_set_int( self, mlt_property_get_int( self, fps, locale ) );
846 // Use the specified locale
849 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
850 // Save the current locale
851 #if defined(__DARWIN__)
852 localename = querylocale( LC_NUMERIC, locale );
853 #elif defined(__GLIBC__)
854 localename = locale->__names[ LC_NUMERIC ];
856 // TODO: not yet sure what to do on other platforms
858 // Protect damaging the global locale from a temporary locale on another thread.
859 pthread_mutex_lock( &self->mutex );
861 // Get the current locale
862 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
864 // Set the new locale
865 setlocale( LC_NUMERIC, localename );
869 // Make sure we have a lock before accessing self->types
870 pthread_mutex_lock( &self->mutex );
873 // Convert number to string
874 if ( self->types & mlt_prop_int )
876 self->types |= mlt_prop_string;
877 self->prop_string = malloc( 32 );
878 if ( format == mlt_time_clock )
879 time_clock_from_frames( self->prop_int, fps, self->prop_string );
881 time_smpte_from_frames( self->prop_int, fps, self->prop_string );
883 else if ( self->types & mlt_prop_position )
885 self->types |= mlt_prop_string;
886 self->prop_string = malloc( 32 );
887 if ( format == mlt_time_clock )
888 time_clock_from_frames( (int) self->prop_position, fps, self->prop_string );
890 time_smpte_from_frames( (int) self->prop_position, fps, self->prop_string );
892 else if ( self->types & mlt_prop_double )
894 self->types |= mlt_prop_string;
895 self->prop_string = malloc( 32 );
896 if ( format == mlt_time_clock )
897 time_clock_from_frames( self->prop_double, fps, self->prop_string );
899 time_smpte_from_frames( self->prop_double, fps, self->prop_string );
901 else if ( self->types & mlt_prop_int64 )
903 self->types |= mlt_prop_string;
904 self->prop_string = malloc( 32 );
905 if ( format == mlt_time_clock )
906 time_clock_from_frames( (int) self->prop_int64, fps, self->prop_string );
908 time_smpte_from_frames( (int) self->prop_int64, fps, self->prop_string );
911 // Restore the current locale
914 setlocale( LC_NUMERIC, orig_localename );
915 free( orig_localename );
916 pthread_mutex_unlock( &self->mutex );
920 // Make sure we have a lock before accessing self->types
921 pthread_mutex_unlock( &self->mutex );
924 // Return the string (may be NULL)
925 return self->prop_string;
928 static int is_property_numeric( mlt_property self, locale_t locale )
930 int result = ( self->types & mlt_prop_int ) ||
931 ( self->types & mlt_prop_int64 ) ||
932 ( self->types & mlt_prop_double ) ||
933 ( self->types & mlt_prop_position );
935 // If not already numeric but string is numeric.
936 if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
940 #if defined(__GLIBC__) || defined(__DARWIN__)
942 temp = strtod_l( self->prop_string, &p, locale );
945 temp = strtod( self->prop_string, &p );
946 result = ( p != self->prop_string );
951 static inline double linearstep( double start, double end, double position, int length )
953 double o = ( end - start ) / length;
954 return start + position * o;
957 int mlt_property_interpolate(mlt_property self, mlt_property previous, mlt_property next,
958 double position, int length, double fps, locale_t locale )
961 if ( fps > 0 && is_property_numeric( previous, locale ) && is_property_numeric( next, locale ) )
963 double start = previous? mlt_property_get_double( previous, fps, locale ) : 0;
964 double end = next? mlt_property_get_double( next, fps, locale ) : 0;
965 double value = next? linearstep( start, end, position, length ) : start;
966 error = mlt_property_set_double( self, value );
970 mlt_property_pass( self, previous );