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 s the string to parse
269 * \param fps frames per second
270 * \param locale the locale to use for parsing a real number value
271 * \return position in frames
274 static int time_clock_to_frames( const char *s, double fps, locale_t locale )
276 char *pos, *copy = strdup( s );
277 int hours = 0, minutes = 0;
281 pos = strrchr( s, ':' );
283 #if defined(__GLIBC__) || defined(__DARWIN__)
285 seconds = strtod_l( pos + 1, NULL, locale );
288 seconds = strtod( pos + 1, NULL );
290 pos = strrchr( s, ':' );
292 minutes = atoi( pos + 1 );
301 #if defined(__GLIBC__) || defined(__DARWIN__)
303 seconds = strtod_l( s, NULL, locale );
306 seconds = strtod( s, NULL );
310 return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) );
313 /** Parse a SMPTE timecode string.
315 * \private \memberof mlt_property_s
316 * \param s the string to parse
317 * \param fps frames per second
318 * \return position in frames
321 static int time_code_to_frames( const char *s, double fps )
323 char *pos, *copy = strdup( s );
324 int hours = 0, minutes = 0, seconds = 0, frames;
327 pos = strrchr( s, ';' );
329 pos = strrchr( s, ':' );
331 frames = atoi( pos + 1 );
333 pos = strrchr( s, ':' );
335 seconds = atoi( pos + 1 );
337 pos = strrchr( s, ':' );
339 minutes = atoi( pos + 1 );
356 return lrint( fps * ( (hours * 3600) + (minutes * 60) + seconds ) + frames );
359 /** Convert a string to an integer.
361 * The string must begin with '0x' to be interpreted as hexadecimal.
362 * Otherwise, it is interpreted as base 10.
364 * If the string begins with '#' it is interpreted as a hexadecimal color value
365 * in the form RRGGBB or AARRGGBB. Color values that begin with '0x' are
366 * always in the form RRGGBBAA where the alpha components are not optional.
367 * Applications and services should expect the binary color value in bytes to
368 * be in the following order: RGBA. This means they will have to cast the int
369 * to an unsigned int. This is especially important when they need to shift
370 * right to obtain RGB without alpha in order to make it do a logical instead
371 * of arithmetic shift.
373 * If the string contains a colon it is interpreted as a time value. If it also
374 * contains a period or comma character, the string is parsed as a clock value:
375 * HH:MM:SS. Otherwise, the time value is parsed as a SMPTE timecode: HH:MM:SS:FF.
376 * \private \memberof mlt_property_s
377 * \param value a string to convert
378 * \param fps frames per second, used when converting from time value
379 * \param locale the locale to use when converting from time clock value
380 * \return the resultant integer
382 static int mlt_property_atoi( const char *value, double fps, locale_t locale )
384 // Parse a hex color value as #RRGGBB or #AARRGGBB.
385 if ( value[0] == '#' )
387 unsigned int rgb = strtoul( value + 1, NULL, 16 );
388 unsigned int alpha = ( strlen( value ) > 7 ) ? ( rgb >> 24 ) : 0xff;
389 return ( rgb << 8 ) | alpha;
391 // Do hex and decimal explicitly to avoid decimal value with leading zeros
392 // interpreted as octal.
393 else if ( value[0] == '0' && value[1] == 'x' )
395 return strtoul( value + 2, NULL, 16 );
397 else if ( fps > 0 && strchr( value, ':' ) )
399 if ( strchr( value, '.' ) || strchr( value, ',' ) )
400 return time_clock_to_frames( value, fps, locale );
402 return time_code_to_frames( value, fps );
406 return strtol( value, NULL, 10 );
410 /** Get the property as an integer.
412 * \public \memberof mlt_property_s
413 * \param self a property
414 * \param fps frames per second, used when converting from time value
415 * \param locale the locale to use when converting from time clock value
416 * \return an integer value
419 int mlt_property_get_int( mlt_property self, double fps, locale_t locale )
421 if ( self->types & mlt_prop_int )
422 return self->prop_int;
423 else if ( self->types & mlt_prop_double )
424 return ( int )self->prop_double;
425 else if ( self->types & mlt_prop_position )
426 return ( int )self->prop_position;
427 else if ( self->types & mlt_prop_int64 )
428 return ( int )self->prop_int64;
429 else if ( self->types & mlt_prop_rect && self->data )
430 return ( int ) ( (mlt_rect*) self->data )->x;
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 * If the numeric string ends with '%' then the value is divided by 100 to convert
443 * \private \memberof mlt_property_s
444 * \param value the string to convert
445 * \param fps frames per second, used when converting from time value
446 * \param locale the locale to use when converting from time clock value
447 * \return the resultant real number
449 static double mlt_property_atof( const char *value, double fps, locale_t locale )
451 if ( fps > 0 && strchr( value, ':' ) )
453 if ( strchr( value, '.' ) || strchr( value, ',' ) )
454 return time_clock_to_frames( value, fps, locale );
456 return time_code_to_frames( value, fps );
462 #if defined(__GLIBC__) || defined(__DARWIN__)
464 result = strtod_l( value, &end, locale );
467 result = strtod( value, &end );
468 if ( end && end[0] == '%' )
474 /** Get the property as a floating point.
476 * \public \memberof mlt_property_s
477 * \param self a property
478 * \param fps frames per second, used when converting from time value
479 * \param locale the locale to use for this conversion
480 * \return a floating point value
483 double mlt_property_get_double( mlt_property self, double fps, locale_t locale )
485 if ( self->types & mlt_prop_double )
486 return self->prop_double;
487 else if ( self->types & mlt_prop_int )
488 return ( double )self->prop_int;
489 else if ( self->types & mlt_prop_position )
490 return ( double )self->prop_position;
491 else if ( self->types & mlt_prop_int64 )
492 return ( double )self->prop_int64;
493 else if ( self->types & mlt_prop_rect && self->data )
494 return ( (mlt_rect*) self->data )->x;
495 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
496 return mlt_property_atof( self->prop_string, fps, locale );
500 /** Get the property as a position.
502 * A position is an offset time in terms of frame units.
503 * \public \memberof mlt_property_s
504 * \param self a property
505 * \param fps frames per second, used when converting from time value
506 * \param locale the locale to use when converting from time clock value
507 * \return the position in frames
510 mlt_position mlt_property_get_position( mlt_property self, double fps, locale_t locale )
512 if ( self->types & mlt_prop_position )
513 return self->prop_position;
514 else if ( self->types & mlt_prop_int )
515 return ( mlt_position )self->prop_int;
516 else if ( self->types & mlt_prop_double )
517 return ( mlt_position )self->prop_double;
518 else if ( self->types & mlt_prop_int64 )
519 return ( mlt_position )self->prop_int64;
520 else if ( self->types & mlt_prop_rect && self->data )
521 return ( mlt_position ) ( (mlt_rect*) self->data )->x;
522 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
523 return ( mlt_position )mlt_property_atoi( self->prop_string, fps, locale );
527 /** Convert a string to a 64-bit integer.
529 * If the string begins with '0x' it is interpreted as a hexadecimal value.
530 * \private \memberof mlt_property_s
531 * \param value a string
532 * \return a 64-bit integer
535 static inline int64_t mlt_property_atoll( const char *value )
539 else if ( value[0] == '0' && value[1] == 'x' )
540 return strtoll( value + 2, NULL, 16 );
542 return strtoll( value, NULL, 10 );
545 /** Get the property as a signed integer.
547 * \public \memberof mlt_property_s
548 * \param self a property
549 * \return a 64-bit integer
552 int64_t mlt_property_get_int64( mlt_property self )
554 if ( self->types & mlt_prop_int64 )
555 return self->prop_int64;
556 else if ( self->types & mlt_prop_int )
557 return ( int64_t )self->prop_int;
558 else if ( self->types & mlt_prop_double )
559 return ( int64_t )self->prop_double;
560 else if ( self->types & mlt_prop_position )
561 return ( int64_t )self->prop_position;
562 else if ( self->types & mlt_prop_rect && self->data )
563 return ( int64_t ) ( (mlt_rect*) self->data )->x;
564 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
565 return mlt_property_atoll( self->prop_string );
569 /** Get the property as a string.
571 * The caller is not responsible for deallocating the returned string!
572 * The string is deallocated when the Property is closed.
573 * This tries its hardest to convert the property to string including using
574 * a serialization function for binary data, if supplied.
575 * \public \memberof mlt_property_s
576 * \param self a property
577 * \return a string representation of the property or NULL if failed
580 char *mlt_property_get_string( mlt_property self )
582 // Construct a string if need be
583 if ( ! ( self->types & mlt_prop_string ) )
585 pthread_mutex_lock( &self->mutex );
586 if ( self->types & mlt_prop_int )
588 self->types |= mlt_prop_string;
589 self->prop_string = malloc( 32 );
590 sprintf( self->prop_string, "%d", self->prop_int );
592 else if ( self->types & mlt_prop_double )
594 self->types |= mlt_prop_string;
595 self->prop_string = malloc( 32 );
596 sprintf( self->prop_string, "%g", self->prop_double );
598 else if ( self->types & mlt_prop_position )
600 self->types |= mlt_prop_string;
601 self->prop_string = malloc( 32 );
602 sprintf( self->prop_string, "%d", (int)self->prop_position );
604 else if ( self->types & mlt_prop_int64 )
606 self->types |= mlt_prop_string;
607 self->prop_string = malloc( 32 );
608 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
610 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
612 self->types |= mlt_prop_string;
613 self->prop_string = self->serialiser( self->data, self->length );
615 pthread_mutex_unlock( &self->mutex );
618 // Return the string (may be NULL)
619 return self->prop_string;
622 /** Get the property as a string (with locale).
624 * The caller is not responsible for deallocating the returned string!
625 * The string is deallocated when the Property is closed.
626 * This tries its hardest to convert the property to string including using
627 * a serialization function for binary data, if supplied.
628 * \public \memberof mlt_property_s
629 * \param self a property
630 * \param locale the locale to use for this conversion
631 * \return a string representation of the property or NULL if failed
634 char *mlt_property_get_string_l( mlt_property self, locale_t locale )
636 // Optimization for no locale
638 return mlt_property_get_string( self );
640 // Construct a string if need be
641 if ( ! ( self->types & mlt_prop_string ) )
643 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
644 // Save the current locale
645 #if defined(__DARWIN__)
646 const char *localename = querylocale( LC_NUMERIC, locale );
647 #elif defined(__GLIBC__)
648 const char *localename = locale->__names[ LC_NUMERIC ];
650 // TODO: not yet sure what to do on other platforms
651 const char *localename = NULL;
653 // Protect damaging the global locale from a temporary locale on another thread.
654 pthread_mutex_lock( &self->mutex );
656 // Get the current locale
657 char *orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
659 // Set the new locale
660 setlocale( LC_NUMERIC, localename );
662 if ( self->types & mlt_prop_int )
664 self->types |= mlt_prop_string;
665 self->prop_string = malloc( 32 );
666 sprintf( self->prop_string, "%d", self->prop_int );
668 else if ( self->types & mlt_prop_double )
670 self->types |= mlt_prop_string;
671 self->prop_string = malloc( 32 );
672 sprintf( self->prop_string, "%g", self->prop_double );
674 else if ( self->types & mlt_prop_position )
676 self->types |= mlt_prop_string;
677 self->prop_string = malloc( 32 );
678 sprintf( self->prop_string, "%d", (int)self->prop_position );
680 else if ( self->types & mlt_prop_int64 )
682 self->types |= mlt_prop_string;
683 self->prop_string = malloc( 32 );
684 sprintf( self->prop_string, "%"PRId64, self->prop_int64 );
686 else if ( self->types & mlt_prop_data && self->serialiser != NULL )
688 self->types |= mlt_prop_string;
689 self->prop_string = self->serialiser( self->data, self->length );
691 // Restore the current locale
692 setlocale( LC_NUMERIC, orig_localename );
693 free( orig_localename );
694 pthread_mutex_unlock( &self->mutex );
697 // Return the string (may be NULL)
698 return self->prop_string;
701 /** Get the binary data from a property.
703 * This only works if you previously put binary data into the property.
704 * This does not return a copy of the data; it returns a pointer to it.
705 * If you supplied a destructor function when setting the binary data,
706 * the destructor is used when the Property is closed to free the memory.
707 * Therefore, only free the returned pointer if you did not supply a
708 * destructor function.
709 * \public \memberof mlt_property_s
710 * \param self a property
711 * \param[out] length the size of the binary object in bytes (optional)
712 * \return an opaque data pointer or NULL if not available
715 void *mlt_property_get_data( mlt_property self, int *length )
717 // Assign length if not NULL
718 if ( length != NULL )
719 *length = self->length;
721 // Return the data (note: there is no conversion here)
725 /** Destroy a property and free all related resources.
727 * \public \memberof mlt_property_s
728 * \param self a property
731 void mlt_property_close( mlt_property self )
733 mlt_property_clear( self );
734 pthread_mutex_destroy( &self->mutex );
740 * A Property holding binary data only copies the data if a serialiser
741 * function was supplied when you set the Property.
742 * \public \memberof mlt_property_s
743 * \author Zach <zachary.drew@gmail.com>
744 * \param self a property
745 * \param that another property
747 void mlt_property_pass( mlt_property self, mlt_property that )
749 pthread_mutex_lock( &self->mutex );
750 mlt_property_clear( self );
752 self->types = that->types;
754 if ( self->types & mlt_prop_int64 )
755 self->prop_int64 = that->prop_int64;
756 else if ( self->types & mlt_prop_int )
757 self->prop_int = that->prop_int;
758 else if ( self->types & mlt_prop_double )
759 self->prop_double = that->prop_double;
760 else if ( self->types & mlt_prop_position )
761 self->prop_position = that->prop_position;
762 if ( self->types & mlt_prop_string )
764 if ( that->prop_string != NULL )
765 self->prop_string = strdup( that->prop_string );
767 else if ( that->types & mlt_prop_rect )
769 mlt_property_clear( self );
770 self->types = mlt_prop_rect | mlt_prop_data;
771 self->length = that->length;
772 self->data = calloc( 1, self->length );
773 memcpy( self->data, that->data, self->length );
774 self->destructor = free;
775 self->serialiser = that->serialiser;
777 else if ( self->types & mlt_prop_data && that->serialiser != NULL )
779 self->types = mlt_prop_string;
780 self->prop_string = that->serialiser( that->data, that->length );
782 pthread_mutex_unlock( &self->mutex );
785 /** Convert frame count to a SMPTE timecode string.
787 * \private \memberof mlt_property_s
788 * \param frames a frame count
789 * \param fps frames per second
790 * \param[out] s the string to write into - must have enough space to hold largest time string
793 static void time_smpte_from_frames( int frames, double fps, char *s )
795 int hours, mins, secs;
796 char frame_sep = ':';
798 if ( fps == 30000.0/1001.0 )
801 int i, max_frames = frames;
802 for ( i = 1800; i <= max_frames; i += 1800 )
812 hours = frames / ( fps * 3600 );
813 frames -= hours * ( fps * 3600 );
814 mins = frames / ( fps * 60 );
815 frames -= mins * ( fps * 60 );
817 frames -= secs * fps;
819 sprintf( s, "%02d:%02d:%02d%c%02d", hours, mins, secs, frame_sep, frames );
822 /** Convert frame count to a SMIL clock value string.
824 * \private \memberof mlt_property_s
825 * \param frames a frame count
826 * \param fps frames per second
827 * \param[out] s the string to write into - must have enough space to hold largest time string
830 static void time_clock_from_frames( int frames, double fps, char *s )
835 hours = frames / ( fps * 3600 );
836 frames -= hours * ( fps * 3600 );
837 mins = frames / ( fps * 60 );
838 frames -= mins * ( fps * 60 );
839 secs = (double) frames / fps;
841 sprintf( s, "%02d:%02d:%06.3f", hours, mins, secs );
844 /** Get the property as a time string.
846 * The time value can be either a SMPTE timecode or SMIL clock value.
847 * The caller is not responsible for deallocating the returned string!
848 * The string is deallocated when the property is closed.
849 * \public \memberof mlt_property_s
850 * \param self a property
851 * \param format the time format that you want
852 * \param fps frames per second
853 * \param locale the locale to use for this conversion
854 * \return a string representation of the property or NULL if failed
857 char *mlt_property_get_time( mlt_property self, mlt_time_format format, double fps, locale_t locale )
859 char *orig_localename = NULL;
860 const char *localename = NULL;
862 // Optimization for mlt_time_frames
863 if ( format == mlt_time_frames )
864 return mlt_property_get_string_l( self, locale );
866 // Remove existing string
867 if ( self->prop_string )
868 mlt_property_set_int( self, mlt_property_get_int( self, fps, locale ) );
870 // Use the specified locale
873 // TODO: when glibc gets sprintf_l, start using it! For now, hack on setlocale.
874 // Save the current locale
875 #if defined(__DARWIN__)
876 localename = querylocale( LC_NUMERIC, locale );
877 #elif defined(__GLIBC__)
878 localename = locale->__names[ LC_NUMERIC ];
880 // TODO: not yet sure what to do on other platforms
882 // Protect damaging the global locale from a temporary locale on another thread.
883 pthread_mutex_lock( &self->mutex );
885 // Get the current locale
886 orig_localename = strdup( setlocale( LC_NUMERIC, NULL ) );
888 // Set the new locale
889 setlocale( LC_NUMERIC, localename );
893 // Make sure we have a lock before accessing self->types
894 pthread_mutex_lock( &self->mutex );
897 // Convert number to string
898 if ( self->types & mlt_prop_int )
900 self->types |= mlt_prop_string;
901 self->prop_string = malloc( 32 );
902 if ( format == mlt_time_clock )
903 time_clock_from_frames( self->prop_int, fps, self->prop_string );
905 time_smpte_from_frames( self->prop_int, fps, self->prop_string );
907 else if ( self->types & mlt_prop_position )
909 self->types |= mlt_prop_string;
910 self->prop_string = malloc( 32 );
911 if ( format == mlt_time_clock )
912 time_clock_from_frames( (int) self->prop_position, fps, self->prop_string );
914 time_smpte_from_frames( (int) self->prop_position, fps, self->prop_string );
916 else if ( self->types & mlt_prop_double )
918 self->types |= mlt_prop_string;
919 self->prop_string = malloc( 32 );
920 if ( format == mlt_time_clock )
921 time_clock_from_frames( self->prop_double, fps, self->prop_string );
923 time_smpte_from_frames( self->prop_double, fps, self->prop_string );
925 else if ( self->types & mlt_prop_int64 )
927 self->types |= mlt_prop_string;
928 self->prop_string = malloc( 32 );
929 if ( format == mlt_time_clock )
930 time_clock_from_frames( (int) self->prop_int64, fps, self->prop_string );
932 time_smpte_from_frames( (int) self->prop_int64, fps, self->prop_string );
935 // Restore the current locale
938 setlocale( LC_NUMERIC, orig_localename );
939 free( orig_localename );
940 pthread_mutex_unlock( &self->mutex );
944 // Make sure we have a lock before accessing self->types
945 pthread_mutex_unlock( &self->mutex );
948 // Return the string (may be NULL)
949 return self->prop_string;
952 /** Determine if the property holds a numeric or numeric string value.
954 * \private \memberof mlt_property_s
955 * \param self a property
956 * \param locale the locale to use for string evaluation
957 * \return true if it is numeric
960 static int is_property_numeric( mlt_property self, locale_t locale )
962 int result = ( self->types & mlt_prop_int ) ||
963 ( self->types & mlt_prop_int64 ) ||
964 ( self->types & mlt_prop_double ) ||
965 ( self->types & mlt_prop_position ) ||
966 ( self->types & mlt_prop_rect );
968 // If not already numeric but string is numeric.
969 if ( ( !result && self->types & mlt_prop_string ) && self->prop_string )
973 #if defined(__GLIBC__) || defined(__DARWIN__)
975 temp = strtod_l( self->prop_string, &p, locale );
978 temp = strtod( self->prop_string, &p );
979 result = ( p != self->prop_string );
984 /** A linear interpolation function for animation.
986 * \private \memberof mlt_property_s
989 static inline double linear_interpolate( double y1, double y2, double t )
991 return y1 + ( y2 - y1 ) * t;
994 /** A smooth spline interpolation for animation.
996 * For non-closed curves, you need to also supply the tangent vector at the first and last control point.
997 * This is commonly done: T(P[0]) = P[1] - P[0] and T(P[n]) = P[n] - P[n-1].
998 * \private \memberof mlt_property_s
1001 static inline double catmull_rom_interpolate( double y0, double y1, double y2, double y3, double t )
1004 double a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
1005 double a1 = y0 - 2.5 * y1 + 2 * y2 - 0.5 * y3;
1006 double a2 = -0.5 * y0 + 0.5 * y2;
1008 return a0 * t * t2 + a1 * t2 + a2 * t + a3;
1011 /** Interpolate a new property value given a set of other properties.
1013 * \public \memberof mlt_property_s
1014 * \param self the property onto which to set the computed value
1015 * \param p an array of at least 1 value in p[1] if \p interp is discrete,
1016 * 2 values in p[1] and p[2] if \p interp is linear, or
1017 * 4 values in p[0] - p[3] if \p interp is smooth
1018 * \param progress a ratio in the range [0, 1] to indicate how far between p[1] and p[2]
1019 * \param fps the frame rate, which may be needed for converting a time string to frame units
1020 * \param locale the locale, which may be needed for converting a string to a real number
1021 * \param interp the interpolation method to use
1022 * \return true if there was an error
1025 int mlt_property_interpolate( mlt_property self, mlt_property p[],
1026 double progress, double fps, locale_t locale, mlt_keyframe_type interp )
1029 if ( interp != mlt_keyframe_discrete &&
1030 is_property_numeric( p[1], locale ) && is_property_numeric( p[2], locale ) )
1032 if ( self->types & mlt_prop_rect )
1034 mlt_rect value = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
1035 if ( interp == mlt_keyframe_linear )
1038 mlt_rect zero = {0, 0, 0, 0, 0};
1039 points[0] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
1042 points[1] = mlt_property_get_rect( p[2], locale );
1043 value.x = linear_interpolate( points[0].x, points[1].x, progress );
1044 value.y = linear_interpolate( points[0].y, points[1].y, progress );
1045 value.w = linear_interpolate( points[0].w, points[1].w, progress );
1046 value.h = linear_interpolate( points[0].h, points[1].h, progress );
1047 value.o = linear_interpolate( points[0].o, points[1].o, progress );
1054 else if ( interp == mlt_keyframe_smooth )
1057 mlt_rect zero = {0, 0, 0, 0, 0};
1058 points[1] = p[1]? mlt_property_get_rect( p[1], locale ) : zero;
1061 points[0] = p[0]? mlt_property_get_rect( p[0], locale ) : zero;
1062 points[2] = p[2]? mlt_property_get_rect( p[2], locale ) : zero;
1063 points[3] = p[3]? mlt_property_get_rect( p[3], locale ) : zero;
1064 value.x = catmull_rom_interpolate( points[0].x, points[1].x, points[2].x, points[3].x, progress );
1065 value.y = catmull_rom_interpolate( points[0].y, points[1].y, points[2].y, points[3].y, progress );
1066 value.w = catmull_rom_interpolate( points[0].w, points[1].w, points[2].w, points[3].w, progress );
1067 value.h = catmull_rom_interpolate( points[0].h, points[1].h, points[2].h, points[3].h, progress );
1068 value.o = catmull_rom_interpolate( points[0].o, points[1].o, points[2].o, points[3].o, progress );
1075 error = mlt_property_set_rect( self, value );
1080 if ( interp == mlt_keyframe_linear )
1083 points[0] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
1084 points[1] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
1085 value = p[2]? linear_interpolate( points[0], points[1], progress ) : points[0];
1087 else if ( interp == mlt_keyframe_smooth )
1090 points[0] = p[0]? mlt_property_get_double( p[0], fps, locale ) : 0;
1091 points[1] = p[1]? mlt_property_get_double( p[1], fps, locale ) : 0;
1092 points[2] = p[2]? mlt_property_get_double( p[2], fps, locale ) : 0;
1093 points[3] = p[3]? mlt_property_get_double( p[3], fps, locale ) : 0;
1094 value = p[2]? catmull_rom_interpolate( points[0], points[1], points[2], points[3], progress ) : points[1];
1096 error = mlt_property_set_double( self, value );
1101 mlt_property_pass( self, p[1] );
1106 /** Create a new animation or refresh an existing one.
1108 * \private \memberof mlt_property_s
1109 * \param self a property
1110 * \param fps the frame rate, which may be needed for converting a time string to frame units
1111 * \param locale the locale, which may be needed for converting a string to a real number
1112 * \param length the maximum number of frames when interpreting negative keyframe times,
1113 * <=0 if you don't care or need that
1116 static void refresh_animation( mlt_property self, double fps, locale_t locale, int length )
1118 if ( !self->animation )
1120 self->animation = mlt_animation_new();
1121 if ( self->prop_string )
1123 mlt_animation_parse( self->animation, self->prop_string, length, fps, locale );
1127 mlt_animation_set_length( self->animation, length );
1128 pthread_mutex_lock( &self->mutex );
1129 self->types |= mlt_prop_data;
1130 self->data = self->animation;
1131 self->serialiser = (mlt_serialiser) mlt_animation_serialize;
1132 pthread_mutex_unlock( &self->mutex );
1135 else if ( self->prop_string )
1137 mlt_animation_refresh( self->animation, self->prop_string, length );
1141 /** Get the real number at a frame position.
1143 * \public \memberof mlt_property_s
1144 * \param self a property
1145 * \param fps the frame rate, which may be needed for converting a time string to frame units
1146 * \param locale the locale, which may be needed for converting a string to a real number
1147 * \param position the frame number
1148 * \param length the maximum number of frames when interpreting negative keyframe times,
1149 * <=0 if you don't care or need that
1150 * \return the real number
1153 double mlt_property_anim_get_double( mlt_property self, double fps, locale_t locale, int position, int length )
1155 pthread_mutex_lock( &self->mutex );
1157 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1159 struct mlt_animation_item_s item;
1160 item.property = mlt_property_init();
1162 refresh_animation( self, fps, locale, length );
1163 mlt_animation_get_item( self->animation, &item, position );
1164 result = mlt_property_get_double( item.property, fps, locale );
1166 mlt_property_close( item.property );
1170 result = mlt_property_get_double( self, fps, locale );
1172 pthread_mutex_unlock( &self->mutex );
1176 /** Get the property as an integer number at a frame position.
1178 * \public \memberof mlt_property_s
1179 * \param self a property
1180 * \param fps the frame rate, which may be needed for converting a time string to frame units
1181 * \param locale the locale, which may be needed for converting a string to a real number
1182 * \param position the frame number
1183 * \param length the maximum number of frames when interpreting negative keyframe times,
1184 * <=0 if you don't care or need that
1185 * \return an integer value
1188 int mlt_property_anim_get_int( mlt_property self, double fps, locale_t locale, int position, int length )
1190 pthread_mutex_lock( &self->mutex );
1192 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1194 struct mlt_animation_item_s item;
1195 item.property = mlt_property_init();
1197 refresh_animation( self, fps, locale, length );
1198 mlt_animation_get_item( self->animation, &item, position );
1199 result = mlt_property_get_int( item.property, fps, locale );
1201 mlt_property_close( item.property );
1205 result = mlt_property_get_int( self, fps, locale );
1207 pthread_mutex_unlock( &self->mutex );
1211 /** Get the string at certain a frame position.
1213 * \public \memberof mlt_property_s
1214 * \param self a property
1215 * \param fps the frame rate, which may be needed for converting a time string to frame units
1216 * \param locale the locale, which may be needed for converting a string to a real number
1217 * \param position the frame number
1218 * \param length the maximum number of frames when interpreting negative keyframe times,
1219 * <=0 if you don't care or need that
1220 * \return the string representation of the property or NULL if failed
1223 char* mlt_property_anim_get_string( mlt_property self, double fps, locale_t locale, int position, int length )
1225 pthread_mutex_lock( &self->mutex );
1227 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1229 struct mlt_animation_item_s item;
1230 item.property = mlt_property_init();
1232 if ( !self->animation )
1233 refresh_animation( self, fps, locale, length );
1234 mlt_animation_get_item( self->animation, &item, position );
1236 if ( self->prop_string )
1237 free( self->prop_string );
1238 self->prop_string = mlt_property_get_string_l( item.property, locale );
1239 if ( self->prop_string )
1240 self->prop_string = strdup( self->prop_string );
1241 self->types |= mlt_prop_string;
1243 result = self->prop_string;
1244 mlt_property_close( item.property );
1248 result = mlt_property_get_string_l( self, locale );
1250 pthread_mutex_unlock( &self->mutex );
1254 /** Set a property animation keyframe to a real number.
1256 * \public \memberof mlt_property_s
1257 * \param self a property
1258 * \param value a double precision floating point value
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 * \param keyframe_type the interpolation method for this keyframe
1265 * \return false if successful, true to indicate error
1268 int mlt_property_anim_set_double( mlt_property self, double value, double fps, locale_t locale,
1269 int position, int length, mlt_keyframe_type keyframe_type )
1272 struct mlt_animation_item_s item;
1274 item.property = mlt_property_init();
1275 item.frame = position;
1276 item.keyframe_type = keyframe_type;
1277 mlt_property_set_double( item.property, value );
1279 refresh_animation( self, fps, locale, length );
1280 result = mlt_animation_insert( self->animation, &item );
1281 mlt_animation_interpolate( self->animation );
1282 mlt_property_close( item.property );
1287 /** Set a property animation keyframe to an integer value.
1289 * \public \memberof mlt_property_s
1290 * \param self a property
1291 * \param value an integer
1292 * \param fps the frame rate, which may be needed for converting a time string to frame units
1293 * \param locale the locale, which may be needed for converting a string to a real number
1294 * \param position the frame number
1295 * \param length the maximum number of frames when interpreting negative keyframe times,
1296 * <=0 if you don't care or need that
1297 * \param keyframe_type the interpolation method for this keyframe
1298 * \return false if successful, true to indicate error
1301 int mlt_property_anim_set_int( mlt_property self, int value, double fps, locale_t locale,
1302 int position, int length, mlt_keyframe_type keyframe_type )
1305 struct mlt_animation_item_s item;
1307 item.property = mlt_property_init();
1308 item.frame = position;
1309 item.keyframe_type = keyframe_type;
1310 mlt_property_set_int( item.property, value );
1312 refresh_animation( self, fps, locale, length );
1313 result = mlt_animation_insert( self->animation, &item );
1314 mlt_animation_interpolate( self->animation );
1315 mlt_property_close( item.property );
1320 /** Set a property animation keyframe to a string.
1322 * Strings only support discrete animation. Do not use this to set a property's
1323 * animation string that contains a semicolon-delimited set of values; use
1324 * mlt_property_set() for that.
1325 * \public \memberof mlt_property_s
1326 * \param self a property
1327 * \param value a string
1328 * \param fps the frame rate, which may be needed for converting a time string to frame units
1329 * \param locale the locale, which may be needed for converting a string to a real number
1330 * \param position the frame number
1331 * \param length the maximum number of frames when interpreting negative keyframe times,
1332 * <=0 if you don't care or need that
1333 * \return false if successful, true to indicate error
1336 int mlt_property_anim_set_string( mlt_property self, const char *value, double fps, locale_t locale, int position, int length )
1339 struct mlt_animation_item_s item;
1341 item.property = mlt_property_init();
1342 item.frame = position;
1343 item.keyframe_type = mlt_keyframe_discrete;
1344 mlt_property_set_string( item.property, value );
1346 refresh_animation( self, fps, locale, length );
1347 result = mlt_animation_insert( self->animation, &item );
1348 mlt_animation_interpolate( self->animation );
1349 mlt_property_close( item.property );
1354 /** Get an object's animation object.
1356 * You might need to call another mlt_property_anim_ function to actually construct
1357 * the animation, as this is a simple accessor function.
1358 * \public \memberof mlt_property_s
1359 * \param self a property
1360 * \return the animation object or NULL if there is no animation
1363 mlt_animation mlt_property_get_animation( mlt_property self )
1365 return self->animation;
1368 /** Convert a rectangle value into a string.
1370 * Unlike the deprecated mlt_geometry API, the canonical form of a mlt_rect
1371 * is a space delimited "x y w h o" even though many kinds of field delimiters
1372 * may be used to convert a string to a rectangle.
1373 * \private \memberof mlt_property_s
1374 * \param rect the rectangle to convert
1375 * \param length not used
1376 * \return the string representation of a rectangle
1379 static char* serialise_mlt_rect( mlt_rect *rect, int length )
1381 char* result = calloc( 1, 100 );
1382 if ( rect->x != DBL_MIN )
1383 sprintf( result + strlen( result ), "%g", rect->x );
1384 if ( rect->y != DBL_MIN )
1385 sprintf( result + strlen( result ), " %g", rect->y );
1386 if ( rect->w != DBL_MIN )
1387 sprintf( result + strlen( result ), " %g", rect->w );
1388 if ( rect->h != DBL_MIN )
1389 sprintf( result + strlen( result ), " %g", rect->h );
1390 if ( rect->o != DBL_MIN )
1391 sprintf( result + strlen( result ), " %g", rect->o );
1395 /** Set a property to a mlt_rect rectangle.
1397 * \public \memberof mlt_property_s
1398 * \param self a property
1399 * \param value a rectangle
1403 int mlt_property_set_rect( mlt_property self, mlt_rect value )
1405 pthread_mutex_lock( &self->mutex );
1406 mlt_property_clear( self );
1407 self->types = mlt_prop_rect | mlt_prop_data;
1408 self->length = sizeof(value);
1409 self->data = calloc( 1, self->length );
1410 memcpy( self->data, &value, self->length );
1411 self->destructor = free;
1412 self->serialiser = (mlt_serialiser) serialise_mlt_rect;
1413 pthread_mutex_unlock( &self->mutex );
1417 /** Get the property as a rectangle.
1419 * You can use any non-numeric character(s) as a field delimiter.
1420 * If the number has a '%' immediately following it, the number is divided by
1421 * 100 to convert it into a real number.
1422 * \public \memberof mlt_property_s
1423 * \param self a property
1424 * \param locale the locale to use for when converting from a string
1425 * \return a rectangle value
1428 mlt_rect mlt_property_get_rect( mlt_property self, locale_t locale )
1430 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
1431 if ( self->types & mlt_prop_rect )
1432 rect = *( (mlt_rect*) self->data );
1433 else if ( self->types & mlt_prop_double )
1434 rect.x = self->prop_double;
1435 else if ( self->types & mlt_prop_int )
1436 rect.x = ( double )self->prop_int;
1437 else if ( self->types & mlt_prop_position )
1438 rect.x = ( double )self->prop_position;
1439 else if ( self->types & mlt_prop_int64 )
1440 rect.x = ( double )self->prop_int64;
1441 else if ( ( self->types & mlt_prop_string ) && self->prop_string )
1443 //return mlt_property_atof( self->prop_string, fps, locale );
1444 char *value = self->prop_string;
1450 #if defined(__GLIBC__) || defined(__DARWIN__)
1452 temp = strtod_l( value, &p, locale );
1455 temp = strtod( value, &p );
1464 // Chomp the delimiter.
1467 // Assign the value to appropriate field.
1470 case 0: rect.x = temp; break;
1471 case 1: rect.y = temp; break;
1472 case 2: rect.w = temp; break;
1473 case 3: rect.h = temp; break;
1474 case 4: rect.o = temp; break;
1488 /** Set a property animation keyframe to a rectangle.
1490 * \public \memberof mlt_property_s
1491 * \param self a property
1492 * \param value a rectangle
1493 * \param fps the frame rate, which may be needed for converting a time string to frame units
1494 * \param locale the locale, which may be needed for converting a string to a real number
1495 * \param position the frame number
1496 * \param length the maximum number of frames when interpreting negative keyframe times,
1497 * <=0 if you don't care or need that
1498 * \param keyframe_type the interpolation method for this keyframe
1499 * \return false if successful, true to indicate error
1502 int mlt_property_anim_set_rect( mlt_property self, mlt_rect value, double fps, locale_t locale,
1503 int position, int length, mlt_keyframe_type keyframe_type )
1506 struct mlt_animation_item_s item;
1508 item.property = mlt_property_init();
1509 item.frame = position;
1510 item.keyframe_type = keyframe_type;
1511 mlt_property_set_rect( item.property, value );
1513 refresh_animation( self, fps, locale, length );
1514 result = mlt_animation_insert( self->animation, &item );
1515 mlt_animation_interpolate( self->animation );
1516 mlt_property_close( item.property );
1521 /** Get a rectangle at a frame position.
1523 * \public \memberof mlt_property_s
1524 * \param self a property
1525 * \param fps the frame rate, which may be needed for converting a time string to frame units
1526 * \param locale the locale, which may be needed for converting a string to a real number
1527 * \param position the frame number
1528 * \param length the maximum number of frames when interpreting negative keyframe times,
1529 * <=0 if you don't care or need that
1530 * \return the rectangle
1533 mlt_rect mlt_property_anim_get_rect( mlt_property self, double fps, locale_t locale, int position, int length )
1535 pthread_mutex_lock( &self->mutex );
1537 if ( self->animation || ( ( self->types & mlt_prop_string ) && self->prop_string ) )
1539 struct mlt_animation_item_s item;
1540 item.property = mlt_property_init();
1541 item.property->types = mlt_prop_rect;
1543 refresh_animation( self, fps, locale, length );
1544 mlt_animation_get_item( self->animation, &item, position );
1545 result = mlt_property_get_rect( item.property, locale );
1547 mlt_property_close( item.property );
1551 result = mlt_property_get_rect( self, locale );
1553 pthread_mutex_unlock( &self->mutex );