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"
30 #include "mlt_animation.h"
39 /** Bit pattern used internally to indicated representations available.
44 mlt_prop_none = 0, //!< not set
45 mlt_prop_int = 1, //!< set as an integer
46 mlt_prop_string = 2, //!< set as string or already converted to string
47 mlt_prop_position = 4,//!< set as a position
48 mlt_prop_double = 8, //!< set as a floating point
49 mlt_prop_data = 16, //!< set as opaque binary
50 mlt_prop_int64 = 32 //!< set as a 64-bit integer
54 /** \brief Property class
56 * A property is like a variant or dynamic type. They are used for many things
57 * in MLT, but in particular they are the parameter mechanism for the plugins.
62 /// Stores a bit pattern of types available for this property
63 mlt_property_type types;
65 /// Atomic type handling
67 mlt_position prop_position;
74 /// Generic type handling
77 mlt_destructor destructor;
78 mlt_serialiser serialiser;
80 pthread_mutex_t mutex;
81 mlt_animation animation;
84 /** Construct a property and initialize it
85 * \public \memberof mlt_property_s
88 mlt_property mlt_property_init( )
90 mlt_property self = calloc( 1, sizeof( *self ) );
92 pthread_mutex_init( &self->mutex, NULL );
96 /** Clear (0/null) a property.
98 * Frees up any associated resources in the process.
99 * \private \memberof mlt_property_s
100 * \param self a property
103 static inline void mlt_property_clear( mlt_property self )
105 // Special case data handling
106 if ( self->types & mlt_prop_data && self->destructor != NULL )
107 self->destructor( self->data );
109 // Special case string handling
110 if ( self->types & mlt_prop_string )
111 free( self->prop_string );
113 if ( self->animation )
114 mlt_animation_close( self->animation );
119 self->prop_position = 0;
120 self->prop_double = 0;
121 self->prop_int64 = 0;
122 self->prop_string = NULL;
125 self->destructor = NULL;
126 self->serialiser = NULL;
127 self->animation = NULL;
130 /** Set the property to an integer value.
132 * \public \memberof mlt_property_s
133 * \param self a property
134 * \param value an integer
138 int mlt_property_set_int( mlt_property self, int value )
140 pthread_mutex_lock( &self->mutex );
141 mlt_property_clear( self );
142 self->types = mlt_prop_int;
143 self->prop_int = value;
144 pthread_mutex_unlock( &self->mutex );
148 /** Set the property to a floating point value.
150 * \public \memberof mlt_property_s
151 * \param self a property
152 * \param value a double precision floating point value
156 int mlt_property_set_double( mlt_property self, double value )
158 pthread_mutex_lock( &self->mutex );
159 mlt_property_clear( self );
160 self->types = mlt_prop_double;
161 self->prop_double = value;
162 pthread_mutex_unlock( &self->mutex );
166 /** Set the property to a position value.
168 * Position is a relative time value in frame units.
169 * \public \memberof mlt_property_s
170 * \param self a property
171 * \param value a position value
175 int mlt_property_set_position( mlt_property self, mlt_position value )
177 pthread_mutex_lock( &self->mutex );
178 mlt_property_clear( self );
179 self->types = mlt_prop_position;
180 self->prop_position = value;
181 pthread_mutex_unlock( &self->mutex );
185 /** Set the property to a string value.
187 * This makes a copy of the string you supply so you do not need to track
188 * a new reference to it.
189 * \public \memberof mlt_property_s
190 * \param self a property
191 * \param value the string to copy to the property
192 * \return true if it failed
195 int mlt_property_set_string( mlt_property self, const char *value )
197 pthread_mutex_lock( &self->mutex );
198 if ( value != self->prop_string )
200 mlt_property_clear( self );
201 self->types = mlt_prop_string;
203 self->prop_string = strdup( value );
207 self->types = mlt_prop_string;
209 pthread_mutex_unlock( &self->mutex );
210 return self->prop_string == NULL;
213 /** Set the property to a 64-bit integer value.
215 * \public \memberof mlt_property_s
216 * \param self a property
217 * \param value a 64-bit integer
221 int mlt_property_set_int64( mlt_property self, int64_t value )
223 pthread_mutex_lock( &self->mutex );
224 mlt_property_clear( self );
225 self->types = mlt_prop_int64;
226 self->prop_int64 = value;
227 pthread_mutex_unlock( &self->mutex );
231 /** Set a property to an opaque binary value.
233 * This does not make a copy of the data. You can use a Properties object
234 * with its reference tracking and the destructor function to control
235 * the lifetime of the data. Otherwise, pass NULL for the destructor
236 * function and control the lifetime yourself.
237 * \public \memberof mlt_property_s
238 * \param self a property
239 * \param value an opaque pointer
240 * \param length the number of bytes pointed to by value (optional)
241 * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource)
242 * \param serialiser a function to use to convert this binary data to a string (optional)
246 int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
248 pthread_mutex_lock( &self->mutex );
249 if ( self->data == value )
250 self->destructor = NULL;
251 mlt_property_clear( self );
252 self->types = mlt_prop_data;
254 self->length = length;
255 self->destructor = destructor;
256 self->serialiser = serialiser;
257 pthread_mutex_unlock( &self->mutex );
261 /** Parse a SMIL clock value.
263 * \private \memberof mlt_property_s
264 * \param s the string to parse
265 * \param fps frames per second
266 * \param locale the locale to use for parsing a real number value
267 * \return position in frames
270 static int time_clock_to_frames( const char *s, double fps, locale_t locale )
272 char *pos, *copy = strdup( s );
273 int hours = 0, minutes = 0;
277 pos = strrchr( s, ':' );
279 #if defined(__GLIBC__) || defined(__DARWIN__)
281 seconds = strtod_l( pos + 1, NULL, locale );
284 seconds = strtod( pos + 1, NULL );
286 pos = strrchr( s, ':' );
288 minutes = atoi( pos + 1 );
297 #if defined(__GLIBC__) || defined(__DARWIN__)
299 seconds = strtod_l( s, NULL, locale );
302 seconds = strtod( s, NULL );
306 return fps * ( (hours * 3600) + (minutes * 60) + seconds ) + 0.5;
309 /** Parse a SMPTE timecode string.
311 * \private \memberof mlt_property_s
312 * \param s the string to parse
313 * \param fps frames per second
314 * \return position in frames
317 static int time_code_to_frames( const char *s, double fps )
319 char *pos, *copy = strdup( s );
320 int hours = 0, minutes = 0, seconds = 0, frames;
323 pos = strrchr( s, ';' );
325 pos = strrchr( s, ':' );
327 frames = atoi( pos + 1 );
329 pos = strrchr( s, ':' );
331 seconds = atoi( pos + 1 );
333 pos = strrchr( s, ':' );
335 minutes = atoi( pos + 1 );
352 return frames + ( fps * ( (hours * 3600) + (minutes * 60) + seconds ) + 0.5 );
355 /** Convert a string to an integer.
357 * The string must begin with '0x' to be interpreted as hexadecimal.
358 * Otherwise, it is interpreted as base 10.
360 * If the string begins with '#' it is interpreted as a hexadecimal color value
361 * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
362 * always in the form RRGGBBAA where the alpha components are not optional.
363 * Applications and services should expect the binary color value in bytes to
364 * be in the following order: RGBA. This means they will have to cast the int
365 * to an unsigned int. This is especially important when they need to shift
366 * right to obtain RGB without alpha in order to make it do a logical instead
367 * of arithmetic shift.
369 * If the string contains a colon it is interpreted as a time value. If it also
370 * contains a period or comma character, the string is parsed as a clock value:
371 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
372 * \private \memberof mlt_property_s
373 * \param value a string to convert
374 * \param fps frames per second, used when converting from time value
375 * \param locale the locale to use when converting from time clock value
376 * \return the resultant integer
378 static int mlt_property_atoi( const char *value, double fps, locale_t locale )
380 // Parse a hex color value as #RRGGBB or #AARRGGBB.
381 if ( value[0] == '#' )
383 unsigned int rgb = strtoul( value + 1, NULL, 16 );
384 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
385 return ( rgb << 8 ) | alpha;
387 // Do hex and decimal explicitly to avoid decimal value with leading zeros
388 // interpreted as octal.
389 else if ( value[0] == '0' && value[1] == 'x' )
391 return strtoul( value + 2, NULL, 16 );
393 else if ( fps > 0 && strchr( value, ':' ) )
395 if ( strchr( value, '.' ) || strchr( value, ',' ) )
396 return time_clock_to_frames( value, fps, locale );
398 return time_code_to_frames( value, fps );
402 return strtol( value, NULL, 10 );
406 /** Get the property as an integer.
408 * \public \memberof mlt_property_s
409 * \param self a property
410 * \param fps frames per second, used when converting from time value
411 * \param locale the locale to use when converting from time clock value
412 * \return an integer value
415 int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
417 if ( self->types & mlt_prop_int )
418 return self->prop_int;
419 else if ( self->types & mlt_prop_double )
420 return ( int )self->prop_double;
421 else if ( self->types & mlt_prop_position )
422 return ( int )self->prop_position;
423 else if ( self->types & mlt_prop_int64 )
424 return ( int )self->prop_int64;
425 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
426 return mlt_property_atoi( self->prop_string, fps, locale );
430 /** Convert a string to a floating point number.
432 * If the string contains a colon it is interpreted as a time value. If it also
433 * contains a period or comma character, the string is parsed as a clock value:
434 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
435 * If the numeric string ends with '%' then the value is divided by 100 to convert
437 * \private \memberof mlt_property_s
438 * \param value the string to convert
439 * \param fps frames per second, used when converting from time value
440 * \param locale the locale to use when converting from time clock value
441 * \return the resultant real number
443 static double mlt_property_atof( const char *value, double fps, locale_t locale )
445 if ( fps > 0 && strchr( value, ':' ) )
447 if ( strchr( value, '.' ) || strchr( value, ',' ) )
448 return time_clock_to_frames( value, fps, locale );
450 return time_code_to_frames( value, fps );
456 #if defined(__GLIBC__) || defined(__DARWIN__)
458 result = strtod_l( value, &end, locale );
461 result = strtod( value, &end );
462 if ( *end && end[0] == '%' )
468 /** Get the property as a floating point.
470 * \public \memberof mlt_property_s
471 * \param self a property
472 * \param fps frames per second, used when converting from time value
473 * \param locale the locale to use for this conversion
474 * \return a floating point value
477 double mlt_property_get_double( mlt_property self, double fps, locale_t locale )
479 if ( self->types & mlt_prop_double )
480 return self->prop_double;
481 else if ( self->types & mlt_prop_int )
482 return ( double )self->prop_int;
483 else if ( self->types & mlt_prop_position )
484 return ( double )self->prop_position;
485 else if ( self->types & mlt_prop_int64 )
486 return ( double )self->prop_int64;
487 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
488 return mlt_property_atof( self->prop_string, fps, locale );
492 /** Get the property as a position.
494 * A position is an offset time in terms of frame units.
495 * \public \memberof mlt_property_s
496 * \param self a property
497 * \param fps frames per second, used when converting from time value
498 * \param locale the locale to use when converting from time clock value
499 * \return the position in frames
502 mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t locale )
504 if ( self->types & mlt_prop_position )
505 return self->prop_position;
506 else if ( self->types & mlt_prop_int )
507 return ( mlt_position )self->prop_int;
508 else if ( self->types & mlt_prop_double )
509 return ( mlt_position )self->prop_double;
510 else if ( self->types & mlt_prop_int64 )
511 return ( mlt_position )self->prop_int64;
512 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
513 return ( mlt_position )mlt_property_atoi( self->prop_string, fps, locale );
517 /** Convert a string to a 64-bit integer.
519 * If the string begins with '0x' it is interpreted as a hexadecimal value.
520 * \private \memberof mlt_property_s
521 * \param value a string
522 * \return a 64-bit integer
525 static inline int64_t mlt_property_atoll( const char *value )
529 else if ( value[0] == '0' && value[1] == 'x' )
530 return strtoll( value + 2, NULL, 16 );
532 return strtoll( value, NULL, 10 );
535 /** Get the property as a signed integer.
537 * \public \memberof mlt_property_s
538 * \param self a property
539 * \return a 64-bit integer
542 int64_t mlt_property_get_int64( mlt_property self )
544 if ( self->types & mlt_prop_int64 )
545 return self->prop_int64;
546 else if ( self->types & mlt_prop_int )
547 return ( int64_t )self->prop_int;
548 else if ( self->types & mlt_prop_double )
549 return ( int64_t )self->prop_double;
550 else if ( self->types & mlt_prop_position )
551 return ( int64_t )self->prop_position;
552 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
553 return mlt_property_atoll( self->prop_string );
557 /** Get the property as a string.
559 * The caller is not responsible for deallocating the returned string!
560 * The string is deallocated when the Property is closed.
561 * This tries its hardest to convert the property to string including using
562 * a serialization function for binary data, if supplied.
563 * \public \memberof mlt_property_s
564 * \param self a property
565 * \return a string representation of the property or NULL if failed
568 char *mlt_property_get_string( mlt_property self )
570 // Construct a string if need be
571 if ( ! ( self->types & mlt_prop_string ) )
573 pthread_mutex_lock( &self->mutex );
574 if ( self->types & mlt_prop_int )
576 self->types |= mlt_prop_string;
577 self->prop_string = malloc( 32 );
578 sprintf( self->prop_string, "%d", self->prop_int );
580 else if ( self->types & mlt_prop_double )
582 self->types |= mlt_prop_string;
583 self->prop_string = malloc( 32 );
584 sprintf( self->prop_string, "%f", self->prop_double );
586 else if ( self->types & mlt_prop_position )
588 self->types |= mlt_prop_string;
589 self->prop_string = malloc( 32 );
590 sprintf( self->prop_string, "%d", (int)self->prop_position );
592 else if ( self->types & mlt_prop_int64 )
594 self->types |= mlt_prop_string;
595 self->prop_string = malloc( 32 );
596 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
598 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
600 self->types |= mlt_prop_string;
601 self->prop_string = self->serialiser( self->data, self->length );
603 pthread_mutex_unlock( &self->mutex );
606 // Return the string (may be NULL)
607 return self->prop_string;
610 /** Get the property as a string (with locale).
612 * The caller is not responsible for deallocating the returned string!
613 * The string is deallocated when the Property is closed.
614 * This tries its hardest to convert the property to string including using
615 * a serialization function for binary data, if supplied.
616 * \public \memberof mlt_property_s
617 * \param self a property
618 * \param locale the locale to use for this conversion
619 * \return a string representation of the property or NULL if failed
622 char *mlt_property_get_string_l( mlt_property self, locale_t locale )
624 // Optimization for no locale
626 return mlt_property_get_string( self );
628 // Construct a string if need be
629 if ( ! ( self->types & mlt_prop_string ) )
631 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
632 // Save the current locale
633 #if defined(__DARWIN__)
634 const char *localename = querylocale( LC_NUMERIC, locale );
635 #elif defined(__GLIBC__)
636 const char *localename = locale->__names[ LC_NUMERIC ];
638 // TODO: not yet sure what to do on other platforms
639 const char *localename = "";
641 // Protect damaging the global locale from a temporary locale on another thread.
642 pthread_mutex_lock( &self->mutex );
644 // Get the current locale
645 char *orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
647 // Set the new locale
648 setlocale( LC_NUMERIC, localename );
650 if ( self->types & mlt_prop_int )
652 self->types |= mlt_prop_string;
653 self->prop_string = malloc( 32 );
654 sprintf( self->prop_string, "%d", self->prop_int );
656 else if ( self->types & mlt_prop_double )
658 self->types |= mlt_prop_string;
659 self->prop_string = malloc( 32 );
660 sprintf( self->prop_string, "%f", self->prop_double );
662 else if ( self->types & mlt_prop_position )
664 self->types |= mlt_prop_string;
665 self->prop_string = malloc( 32 );
666 sprintf( self->prop_string, "%d", (int)self->prop_position );
668 else if ( self->types & mlt_prop_int64 )
670 self->types |= mlt_prop_string;
671 self->prop_string = malloc( 32 );
672 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
674 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
676 self->types |= mlt_prop_string;
677 self->prop_string = self->serialiser( self->data, self->length );
679 // Restore the current locale
680 setlocale( LC_NUMERIC, orig_localename );
681 free( orig_localename );
682 pthread_mutex_unlock( &self->mutex );
685 // Return the string (may be NULL)
686 return self->prop_string;
689 /** Get the binary data from a property.
691 * This only works if you previously put binary data into the property.
692 * This does not return a copy of the data; it returns a pointer to it.
693 * If you supplied a destructor function when setting the binary data,
694 * the destructor is used when the Property is closed to free the memory.
695 * Therefore, only free the returned pointer if you did not supply a
696 * destructor function.
697 * \public \memberof mlt_property_s
698 * \param self a property
699 * \param[out] length the size of the binary object in bytes (optional)
700 * \return an opaque data pointer or NULL if not available
703 void *mlt_property_get_data( mlt_property self, int *length )
705 // Assign length if not NULL
706 if ( length != NULL )
707 *length = self->length;
709 // Return the data (note: there is no conversion here)
713 /** Destroy a property and free all related resources.
715 * \public \memberof mlt_property_s
716 * \param self a property
719 void mlt_property_close( mlt_property self )
721 mlt_property_clear( self );
722 pthread_mutex_destroy( &self->mutex );
728 * A Property holding binary data only copies the data if a serialiser
729 * function was supplied when you set the Property.
730 * \public \memberof mlt_property_s
731 * \author Zach <zachary.drew@gmail.com>
732 * \param self a property
733 * \param that another property
735 void mlt_property_pass( mlt_property self, mlt_property that )
737 pthread_mutex_lock( &self->mutex );
738 mlt_property_clear( self );
740 self->types = that->types;
742 if ( self->types & mlt_prop_int64 )
743 self->prop_int64 = that->prop_int64;
744 else if ( self->types & mlt_prop_int )
745 self->prop_int = that->prop_int;
746 else if ( self->types & mlt_prop_double )
747 self->prop_double = that->prop_double;
748 else if ( self->types & mlt_prop_position )
749 self->prop_position = that->prop_position;
750 if ( self->types & mlt_prop_string )
752 if ( that->prop_string != NULL )
753 self->prop_string = strdup( that->prop_string );
755 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
757 self->types = mlt_prop_string;
758 self->prop_string = self->serialiser( self->data, self->length );
760 pthread_mutex_unlock( &self->mutex );
763 /** Convert frame count to a SMPTE timecode string.
765 * \private \memberof mlt_property_s
766 * \param frames a frame count
767 * \param fps frames per second
768 * \param[out] s the string to write into - must have enough space to hold largest time string
771 static void time_smpte_from_frames( int frames, double fps, char *s )
773 int hours, mins, secs;
774 char frame_sep = ':';
776 if ( fps == 30000.0/1001.0 )
779 int i, max_frames = frames;
780 for ( i = 1800; i <= max_frames; i += 1800 )
790 hours = frames / ( fps * 3600 );
791 frames -= hours * ( fps * 3600 );
792 mins = frames / ( fps * 60 );
793 frames -= mins * ( fps * 60 );
795 frames -= secs * fps;
797 sprintf( s, "%02d:%02d:%02d%c%02d", hours, mins, secs, frame_sep, frames );
800 /** Convert frame count to a SMIL clock value string.
802 * \private \memberof mlt_property_s
803 * \param frames a frame count
804 * \param fps frames per second
805 * \param[out] s the string to write into - must have enough space to hold largest time string
808 static void time_clock_from_frames( int frames, double fps, char *s )
813 hours = frames / ( fps * 3600 );
814 frames -= hours * ( fps * 3600 );
815 mins = frames / ( fps * 60 );
816 frames -= mins * ( fps * 60 );
817 secs = (double) frames / fps;
819 sprintf( s, "%02d:%02d:%06.3f", hours, mins, secs );
822 /** Get the property as a time string.
824 * The time value can be either a SMPTE timecode or SMIL clock value.
825 * The caller is not responsible for deallocating the returned string!
826 * The string is deallocated when the property is closed.
827 * \public \memberof mlt_property_s
828 * \param self a property
829 * \param format the time format that you want
830 * \param fps frames per second
831 * \param locale the locale to use for this conversion
832 * \return a string representation of the property or NULL if failed
835 char *mlt_property_get_time( mlt_property self, mlt_time_format format, double fps, locale_t locale )
837 char *orig_localename = NULL;
838 const char *localename = "";
840 // Optimization for mlt_time_frames
841 if ( format == mlt_time_frames )
842 return mlt_property_get_string_l( self, locale );
844 // Remove existing string
845 if ( self->prop_string )
846 mlt_property_set_int( self, mlt_property_get_int( self, fps, locale ) );
848 // Use the specified locale
851 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
852 // Save the current locale
853 #if defined(__DARWIN__)
854 localename = querylocale( LC_NUMERIC, locale );
855 #elif defined(__GLIBC__)
856 localename = locale->__names[ LC_NUMERIC ];
858 // TODO: not yet sure what to do on other platforms
860 // Protect damaging the global locale from a temporary locale on another thread.
861 pthread_mutex_lock( &self->mutex );
863 // Get the current locale
864 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
866 // Set the new locale
867 setlocale( LC_NUMERIC, localename );
871 // Make sure we have a lock before accessing self->types
872 pthread_mutex_lock( &self->mutex );
875 // Convert number to string
876 if ( self->types & mlt_prop_int )
878 self->types |= mlt_prop_string;
879 self->prop_string = malloc( 32 );
880 if ( format == mlt_time_clock )
881 time_clock_from_frames( self->prop_int, fps, self->prop_string );
883 time_smpte_from_frames( self->prop_int, fps, self->prop_string );
885 else if ( self->types & mlt_prop_position )
887 self->types |= mlt_prop_string;
888 self->prop_string = malloc( 32 );
889 if ( format == mlt_time_clock )
890 time_clock_from_frames( (int) self->prop_position, fps, self->prop_string );
892 time_smpte_from_frames( (int) self->prop_position, fps, self->prop_string );
894 else if ( self->types & mlt_prop_double )
896 self->types |= mlt_prop_string;
897 self->prop_string = malloc( 32 );
898 if ( format == mlt_time_clock )
899 time_clock_from_frames( self->prop_double, fps, self->prop_string );
901 time_smpte_from_frames( self->prop_double, fps, self->prop_string );
903 else if ( self->types & mlt_prop_int64 )
905 self->types |= mlt_prop_string;
906 self->prop_string = malloc( 32 );
907 if ( format == mlt_time_clock )
908 time_clock_from_frames( (int) self->prop_int64, fps, self->prop_string );
910 time_smpte_from_frames( (int) self->prop_int64, fps, self->prop_string );
913 // Restore the current locale
916 setlocale( LC_NUMERIC, orig_localename );
917 free( orig_localename );
918 pthread_mutex_unlock( &self->mutex );
922 // Make sure we have a lock before accessing self->types
923 pthread_mutex_unlock( &self->mutex );
926 // Return the string (may be NULL)
927 return self->prop_string;
930 static int is_property_numeric( mlt_property self, locale_t locale )
932 int result = ( self->types & mlt_prop_int ) ||
933 ( self->types & mlt_prop_int64 ) ||
934 ( self->types & mlt_prop_double ) ||
935 ( self->types & mlt_prop_position );
937 // If not already numeric but string is numeric.
938 if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
942 #if defined(__GLIBC__) || defined(__DARWIN__)
944 temp = strtod_l( self->prop_string, &p, locale );
947 temp = strtod( self->prop_string, &p );
948 result = ( p != self->prop_string );
953 static inline double linear_interpolate( double y1, double y2, double t )
955 return y1 + ( y2 - y1 ) * t;
958 // For non-closed curves, you need to also supply the tangent vector at the first and last control point.
959 // This is commonly done: T(P[0]) = P[1] - P[0] and T(P[n]) = P[n] - P[n-1].
960 static inline double catmull_rom_interpolate( double y0, double y1, double y2, double y3, double t )
963 double a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
964 double a1 = y0 - 2.5 * y1 + 2 * y2 - 0.5 * y3;
965 double a2 = -0.5 * y0 + 0.5 * y2;
967 return a0 * t * t2 + a1 * t2 + a2 * t + a3;
970 int mlt_property_interpolate( mlt_property self, mlt_property p[],
971 double progress, double fps, locale_t locale, mlt_keyframe_type interp )
974 if ( interp != mlt_keyframe_discrete &&
975 is_property_numeric( p[1], locale ) && is_property_numeric( p[2], locale ) )
978 if ( interp == mlt_keyframe_linear )
981 points[0] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
982 points[1] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
983 value = p[2]? linear_interpolate( points[0], points[1], progress ) : points[0];
985 else if ( interp == mlt_keyframe_smooth )
988 points[0] = p[0]? mlt_property_get_double( p[0], fps, locale ) : 0;
989 points[1] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
990 points[2] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
991 points[3] = p[3]? mlt_property_get_double( p[3], fps, locale ) : 0;
992 value = p[2]? catmull_rom_interpolate( points[0], points[1], points[2], points[3], progress ) : points[1];
994 error = mlt_property_set_double( self, value );
998 mlt_property_pass( self, p[1] );
1003 static void refresh_animation( mlt_property self, double fps, locale_t locale, int length )
1005 if ( !self->animation )
1007 self->animation = mlt_animation_new();
1008 if ( self->prop_string )
1010 mlt_animation_parse( self->animation, self->prop_string, length, fps, locale );
1014 mlt_animation_set_length( self->animation, length );
1015 self->types |= mlt_prop_data;
1016 self->data = self->animation;
1017 self->serialiser = (mlt_serialiser) mlt_animation_serialize;
1020 else if ( self->prop_string )
1022 mlt_animation_refresh( self->animation, self->prop_string, length );
1026 double mlt_property_get_double_pos( mlt_property self, double fps, locale_t locale, int position, int length )
1029 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1031 struct mlt_animation_item_s item;
1032 item.property = mlt_property_init();
1034 refresh_animation( self, fps, locale, length );
1035 mlt_animation_get_item( self->animation, &item, position );
1036 result = mlt_property_get_double( item.property, fps, locale );
1038 mlt_property_close( item.property );
1042 result = mlt_property_get_double( self, fps, locale );
1047 int mlt_property_get_int_pos( mlt_property self, double fps, locale_t locale, int position, int length )
1050 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1052 struct mlt_animation_item_s item;
1053 item.property = mlt_property_init();
1055 refresh_animation( self, fps, locale, length );
1056 mlt_animation_get_item( self->animation, &item, position );
1057 result = mlt_property_get_int( item.property, fps, locale );
1059 mlt_property_close( item.property );
1063 result = mlt_property_get_int( self, fps, locale );
1068 /** Set a property animation keyframe to a real number.
1070 * \public \memberof mlt_property_s
1071 * \param self a property
1072 * \param value a double precision floating point value
1073 * \return false if successful, true to indicate error
1076 int mlt_property_set_double_pos( mlt_property self, double value, double fps, locale_t locale,
1077 mlt_keyframe_type keyframe_type, int position, int length )
1080 struct mlt_animation_item_s item;
1082 item.property = mlt_property_init();
1083 item.frame = position;
1084 item.keyframe_type = keyframe_type;
1085 mlt_property_set_double( item.property, value );
1087 refresh_animation( self, fps, locale, length );
1088 result = mlt_animation_insert( self->animation, &item );
1089 mlt_animation_interpolate( self->animation );
1090 mlt_property_close( item.property );
1095 /** Set a property animation keyframe to an integer value.
1097 * \public \memberof mlt_property_s
1098 * \param self a property
1099 * \param value a double precision floating point value
1100 * \return false if successful, true to indicate error
1103 int mlt_property_set_int_pos( mlt_property self, int value, double fps, locale_t locale,
1104 mlt_keyframe_type keyframe_type, int position, int length )
1107 struct mlt_animation_item_s item;
1109 item.property = mlt_property_init();
1110 item.frame = position;
1111 item.keyframe_type = keyframe_type;
1112 mlt_property_set_int( item.property, value );
1114 refresh_animation( self, fps, locale, length );
1115 result = mlt_animation_insert( self->animation, &item );
1116 mlt_animation_interpolate( self->animation );
1117 mlt_property_close( item.property );