2 * \file mlt_properties.c
3 * \brief Properties class definition
4 * \see mlt_properties_s
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_properties.h"
31 #include "mlt_property.h"
32 #include "mlt_deque.h"
34 #include "mlt_factory.h"
42 #include <sys/types.h>
49 #define PRESETS_DIR "/presets"
51 /** \brief private implementation of the property list */
60 mlt_properties mirror;
62 pthread_mutex_t mutex;
67 /* Memory leak checks */
69 //#define _MLT_PROPERTY_CHECKS_ 2
70 #ifdef _MLT_PROPERTY_CHECKS_
71 static int properties_created = 0;
72 static int properties_destroyed = 0;
75 /** Initialize a properties object that was already allocated.
77 * This does allocate its ::property_list, and it adds a reference count.
78 * \public \memberof mlt_properties_s
79 * \param self the properties structure to initialize
80 * \param child an opaque pointer to a subclass object
81 * \return true if failed
84 int mlt_properties_init( mlt_properties self, void *child )
88 #ifdef _MLT_PROPERTY_CHECKS_
89 // Increment number of properties created
90 properties_created ++;
94 memset( self, 0, sizeof( struct mlt_properties_s ) );
96 // Assign the child of the object
99 // Allocate the local structure
100 self->local = calloc( 1, sizeof( property_list ) );
102 // Increment the ref count
103 ( ( property_list * )self->local )->ref_count = 1;
104 pthread_mutex_init( &( ( property_list * )self->local )->mutex, NULL );;
107 // Check that initialisation was successful
108 return self != NULL && self->local == NULL;
111 /** Create a properties object.
113 * This allocates the properties structure and calls mlt_properties_init() on it.
114 * Free the properties object with mlt_properties_close().
115 * \public \memberof mlt_properties_s
116 * \return a new properties object
119 mlt_properties mlt_properties_new( )
121 // Construct a standalone properties object
122 mlt_properties self = calloc( 1, sizeof( struct mlt_properties_s ) );
125 mlt_properties_init( self, NULL );
127 // Return the pointer
131 /** Set the numeric locale used for string/double conversions.
133 * \public \memberof mlt_properties_s
134 * \param self a properties list
135 * \param locale the locale name
136 * \return true if error
139 int mlt_properties_set_lcnumeric( mlt_properties self, const char *locale )
143 if ( self && locale )
145 property_list *list = self->local;
147 #if defined(__linux__) || defined(__DARWIN__)
149 freelocale( list->locale );
150 list->locale = newlocale( LC_NUMERIC_MASK, locale, NULL );
152 error = list->locale == NULL;
160 /** Get the numeric locale for this properties object.
162 * Do not free the result.
163 * \public \memberof mlt_properties_s
164 * \param self a properties list
165 * \return the locale name if this properties has a specific locale it is using, NULL otherwise
168 const char* mlt_properties_get_lcnumeric( mlt_properties self )
170 property_list *list = self->local;
171 const char *result = NULL;
175 #if defined(__DARWIN__)
176 result = querylocale( LC_NUMERIC, list->locale );
177 #elif defined(__linux__)
178 result = list->locale->__names[ LC_NUMERIC ];
180 // TODO: not yet sure what to do on other platforms
186 static int load_properties( mlt_properties self, const char *filename )
189 FILE *file = fopen( filename, "r" );
191 // Load contents of file
196 char last[ 1024 ] = "";
198 // Read each string from the file
199 while( fgets( temp, 1024, file ) )
201 // Chomp the new line character from the string
202 int x = strlen( temp ) - 1;
203 if ( temp[x] == '\n' || temp[x] == '\r' )
206 // Check if the line starts with a .
207 if ( temp[ 0 ] == '.' )
210 sprintf( temp2, "%s%s", last, temp );
211 strcpy( temp, temp2 );
213 else if ( strchr( temp, '=' ) )
215 strcpy( last, temp );
216 *( strchr( last, '=' ) ) = '\0';
219 // Parse and set the property
220 if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
221 mlt_properties_parse( self, temp );
227 return file? 0 : errno;
230 /** Create a properties object by reading a .properties text file.
232 * Free the properties object with mlt_properties_close().
233 * \deprecated Please start using mlt_properties_parse_yaml().
234 * \public \memberof mlt_properties_s
235 * \param filename the absolute file name
236 * \return a new properties object
239 mlt_properties mlt_properties_load( const char *filename )
241 // Construct a standalone properties object
242 mlt_properties self = mlt_properties_new( );
245 load_properties( self, filename );
247 // Return the pointer
251 /** Set properties from a preset.
253 * Presets are typically installed to $prefix/share/mlt/presets/{type}/{service}/[{profile}/]{name}.
254 * For example, "/usr/share/mlt/presets/consumer/avformat/dv_ntsc_wide/DVD"
255 * could be an encoding preset for a widescreen NTSC DVD Video.
256 * Do not specify the type and service in the preset name parameter; these are
257 * inferred automatically from the service to which you are applying the preset.
258 * Using the example above and assuming you are calling this function on the
259 * avformat consumer, the name passed to the function should simply be DVD.
260 * Note that the profile portion of the path is optional, but a profile-specific
261 * preset with the same name as a more generic one is given a higher priority.
262 * \todo Look in a user-specific location - somewhere in the home directory.
264 * \public \memberof mlt_properties_s
265 * \param self a properties list
266 * \param name the name of a preset in a well-known location or the explicit path
267 * \return true if error
270 int mlt_properties_preset( mlt_properties self, const char *name )
272 struct stat stat_buff;
275 if ( !( self && name && strlen( name ) ) )
278 // See if name is an explicit file
279 if ( ! stat( name, &stat_buff ) )
281 return load_properties( self, name );
285 // Look for profile-specific preset before a generic one.
286 char *data = getenv( "MLT_PRESETS_PATH" );
287 const char *type = mlt_properties_get( self, "mlt_type" );
288 const char *service = mlt_properties_get( self, "mlt_service" );
289 const char *profile = mlt_environment( "MLT_PROFILE" );
294 data = strdup( data );
298 data = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + strlen( PRESETS_DIR ) + 1 );
299 strcpy( data, mlt_environment( "MLT_DATA" ) );
300 strcat( data, PRESETS_DIR );
302 if ( data && type && service )
304 char *path = malloc( 5 + strlen(name) + strlen(data) + strlen(type) + strlen(service) + ( profile? strlen(profile) : 0 ) );
305 sprintf( path, "%s/%s/%s/%s/%s", data, type, service, profile, name );
306 if ( load_properties( self, path ) )
308 sprintf( path, "%s/%s/%s/%s", data, type, service, name );
309 error = load_properties( self, path );
322 /** Generate a hash key.
324 * \private \memberof mlt_properties_s
325 * \param name a string
329 static inline int generate_hash( const char *name )
331 unsigned int hash = 5381;
333 hash = hash * 33 + (unsigned int) ( *name ++ );
337 /** Copy a serializable property to a properties list that is mirroring this one.
339 * Special case - when a container (such as loader) is protecting another
340 * producer, we need to ensure that properties are passed through to the
342 * \private \memberof mlt_properties_s
343 * \param self a properties list
344 * \param name the name of the property to copy
347 static inline void mlt_properties_do_mirror( mlt_properties self, const char *name )
350 property_list *list = self->local;
351 if ( list->mirror != NULL )
353 char *value = mlt_properties_get( self, name );
355 mlt_properties_set( list->mirror, name, value );
359 /** Increment the reference count.
361 * \public \memberof mlt_properties_s
362 * \param self a properties list
363 * \return the new reference count
366 int mlt_properties_inc_ref( mlt_properties self )
371 property_list *list = self->local;
372 pthread_mutex_lock( &list->mutex );
373 result = ++ list->ref_count;
374 pthread_mutex_unlock( &list->mutex );
379 /** Decrement the reference count.
381 * \public \memberof mlt_properties_s
382 * \param self a properties list
383 * \return the new reference count
386 int mlt_properties_dec_ref( mlt_properties self )
391 property_list *list = self->local;
392 pthread_mutex_lock( &list->mutex );
393 result = -- list->ref_count;
394 pthread_mutex_unlock( &list->mutex );
399 /** Get the reference count.
401 * \public \memberof mlt_properties_s
402 * \param self a properties list
403 * \return the current reference count
406 int mlt_properties_ref_count( mlt_properties self )
410 property_list *list = self->local;
411 return list->ref_count;
416 /** Set a properties list to be a mirror copy of another.
418 * Note that this does not copy all existing properties. Rather, you must
419 * call this before setting the properties that you wish to copy.
420 * \public \memberof mlt_properties_s
421 * \param that the properties which will receive copies of the properties as they are set.
422 * \param self the properties to mirror
425 void mlt_properties_mirror( mlt_properties self, mlt_properties that )
428 property_list *list = self->local;
432 /** Copy all serializable properties to another properties list.
434 * \public \memberof mlt_properties_s
435 * \param self The properties to copy to
436 * \param that The properties to copy from
437 * \return true if error
440 int mlt_properties_inherit( mlt_properties self, mlt_properties that )
442 if ( !self || !that ) return 1;
443 int count = mlt_properties_count( that );
445 for ( i = 0; i < count; i ++ )
447 char *value = mlt_properties_get_value( that, i );
450 char *name = mlt_properties_get_name( that, i );
451 mlt_properties_set( self, name, value );
457 /** Pass all serializable properties that match a prefix to another properties object
459 * \warning The prefix is stripped from the name when it is set on the \p self properties list!
460 * For example a property named "foo.bar" will match prefix "foo.", but the property
461 * will be named simply "bar" on the receiving properties object.
462 * \public \memberof mlt_properties_s
463 * \param self the properties to copy to
464 * \param that The properties to copy from
465 * \param prefix the property names to match (required)
466 * \return true if error
469 int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix )
471 if ( !self || !that ) return 1;
472 int count = mlt_properties_count( that );
473 int length = strlen( prefix );
475 for ( i = 0; i < count; i ++ )
477 char *name = mlt_properties_get_name( that, i );
478 if ( !strncmp( name, prefix, length ) )
480 char *value = mlt_properties_get_value( that, i );
482 mlt_properties_set( self, name + length, value );
488 /** Locate a property by name.
490 * \private \memberof mlt_properties_s
491 * \param self a properties list
492 * \param name the property to lookup by name
493 * \return the property or NULL for failure
496 static inline mlt_property mlt_properties_find( mlt_properties self, const char *name )
498 if ( !self || !name ) return NULL;
499 property_list *list = self->local;
500 mlt_property value = NULL;
501 int key = generate_hash( name );
503 mlt_properties_lock( self );
505 int i = list->hash[ key ] - 1;
508 // Check if we're hashed
509 if ( list->count > 0 &&
510 name[ 0 ] == list->name[ i ][ 0 ] &&
511 !strcmp( list->name[ i ], name ) )
512 value = list->value[ i ];
515 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
516 if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
517 value = list->value[ i ];
519 mlt_properties_unlock( self );
524 /** Add a new property.
526 * \private \memberof mlt_properties_s
527 * \param self a properties list
528 * \param name the name of the new property
529 * \return the new property
532 static mlt_property mlt_properties_add( mlt_properties self, const char *name )
534 property_list *list = self->local;
535 int key = generate_hash( name );
538 mlt_properties_lock( self );
540 // Check that we have space and resize if necessary
541 if ( list->count == list->size )
544 list->name = realloc( list->name, list->size * sizeof( const char * ) );
545 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
548 // Assign name/value pair
549 list->name[ list->count ] = strdup( name );
550 list->value[ list->count ] = mlt_property_init( );
552 // Assign to hash table
553 if ( list->hash[ key ] == 0 )
554 list->hash[ key ] = list->count + 1;
556 // Return and increment count accordingly
557 result = list->value[ list->count ++ ];
559 mlt_properties_unlock( self );
564 /** Fetch a property by name and add one if not found.
566 * \private \memberof mlt_properties_s
567 * \param self a properties list
568 * \param name the property to lookup or add
569 * \return the property
572 static mlt_property mlt_properties_fetch( mlt_properties self, const char *name )
574 // Try to find an existing property first
575 mlt_property property = mlt_properties_find( self, name );
577 // If it wasn't found, create one
578 if ( property == NULL )
579 property = mlt_properties_add( self, name );
581 // Return the property
585 /** Copy a property to another properties list.
587 * \public \memberof mlt_properties_s
588 * \author Zach <zachary.drew@gmail.com>
589 * \param self the properties to copy to
590 * \param that the properties to copy from
591 * \param name the name of the property to copy
594 void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name )
596 // Make sure the source property isn't null.
597 mlt_property that_prop = mlt_properties_find( that, name );
598 if( that_prop == NULL )
601 mlt_property_pass( mlt_properties_fetch( self, name ), that_prop );
604 /** Copy all properties specified in a comma-separated list to another properties list.
606 * White space is also a delimiter.
607 * \public \memberof mlt_properties_s
608 * \author Zach <zachary.drew@gmail.com>
609 * \param self the properties to copy to
610 * \param that the properties to copy from
611 * \param list a delimited list of property names
612 * \return true if error
616 int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list )
618 if ( !self || !that || !list ) return 1;
619 char *props = strdup( list );
621 const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines
626 count = strcspn( ptr, delim );
628 if( ptr[count] == '\0' )
631 ptr[count] = '\0'; // Make it a real string
633 mlt_properties_pass_property( self, that, ptr );
637 ptr += strspn( ptr, delim );
646 /** Set a property to a string.
648 * The property name "properties" is reserved to load the preset in \p value.
649 * When the value begins with '@' then it is interpreted as a very simple math
650 * expression containing only the +, -, *, and / operators.
651 * The event "property-changed" is fired after the property has been set.
653 * This makes a copy of the string value you supply.
654 * \public \memberof mlt_properties_s
655 * \param self a properties list
656 * \param name the property to set
657 * \param value the property's new value
658 * \return true if error
661 int mlt_properties_set( mlt_properties self, const char *name, const char *value )
665 if ( !self || !name ) return error;
667 // Fetch the property to work with
668 mlt_property property = mlt_properties_fetch( self, name );
670 // Set it if not NULL
671 if ( property == NULL )
673 mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name );
675 else if ( value == NULL )
677 error = mlt_property_set_string( property, value );
678 mlt_properties_do_mirror( self, name );
680 else if ( *value != '@' )
682 error = mlt_property_set_string( property, value );
683 mlt_properties_do_mirror( self, name );
684 if ( !strcmp( name, "properties" ) )
685 mlt_properties_preset( self, value );
687 else if ( value[ 0 ] == '@' )
696 while ( *value != '\0' )
698 int length = strcspn( value, "+-*/" );
700 // Get the identifier
701 strncpy( id, value, length );
705 // Determine the value
706 if ( isdigit( id[ 0 ] ) )
708 #if defined(__GLIBC__) || defined(__DARWIN__)
709 property_list *list = self->local;
711 current = strtod_l( id, NULL, list->locale );
714 current = strtod( id, NULL );
718 current = mlt_properties_get_double( self, id );
721 // Apply the operation
734 total = total / current;
739 op = *value != '\0' ? *value ++ : ' ';
742 error = mlt_property_set_double( property, total );
743 mlt_properties_do_mirror( self, name );
746 mlt_events_fire( self, "property-changed", name, NULL );
751 /** Set or default a property to a string.
753 * This makes a copy of the string value you supply.
754 * \public \memberof mlt_properties_s
755 * \param self a properties list
756 * \param name the property to set
757 * \param value the string value to set or NULL to use the default
758 * \param def the default string if value is NULL
759 * \return true if error
762 int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def )
764 return mlt_properties_set( self, name, value == NULL ? def : value );
767 /** Get a string value by name.
769 * Do not free the returned string. It's lifetime is controlled by the property
770 * and this properties object.
771 * \public \memberof mlt_properties_s
772 * \param self a properties list
773 * \param name the property to get
774 * \return the property's string value or NULL if it does not exist
777 char *mlt_properties_get( mlt_properties self, const char *name )
780 mlt_property value = mlt_properties_find( self, name );
783 property_list *list = self->local;
784 result = mlt_property_get_string_l( value, list->locale );
789 /** Get a property name by index.
791 * Do not free the returned string.
792 * \public \memberof mlt_properties_s
793 * \param self a properties list
794 * \param index the numeric index of the property
795 * \return the name of the property or NULL if index is out of range
798 char *mlt_properties_get_name( mlt_properties self, int index )
800 if ( !self ) return NULL;
801 property_list *list = self->local;
802 if ( index >= 0 && index < list->count )
803 return list->name[ index ];
807 /** Get a property's string value by index.
809 * Do not free the returned string.
810 * \public \memberof mlt_properties_s
811 * \param self a properties list
812 * \param index the numeric index of the property
813 * \return the property value as a string or NULL if the index is out of range
816 char *mlt_properties_get_value( mlt_properties self, int index )
818 if ( !self ) return NULL;
819 property_list *list = self->local;
820 if ( index >= 0 && index < list->count )
821 return mlt_property_get_string_l( list->value[ index ], list->locale );
825 /** Get a data value by index.
827 * Do not free the returned pointer if you supplied a destructor function when you
829 * \public \memberof mlt_properties_s
830 * \param self a properties list
831 * \param index the numeric index of the property
832 * \param[out] size the size of the binary data in bytes or NULL if the index is out of range
835 void *mlt_properties_get_data_at( mlt_properties self, int index, int *size )
837 if ( !self ) return NULL;
838 property_list *list = self->local;
839 if ( index >= 0 && index < list->count )
840 return mlt_property_get_data( list->value[ index ], size );
844 /** Return the number of items in the list.
846 * \public \memberof mlt_properties_s
847 * \param self a properties list
848 * \return the number of property objects or -1 if error
851 int mlt_properties_count( mlt_properties self )
853 if ( !self ) return -1;
854 property_list *list = self->local;
858 /** Set a value by parsing a name=value string.
860 * \public \memberof mlt_properties_s
861 * \param self a properties list
862 * \param namevalue a string containing name and value delimited by '='
863 * \return true if there was an error
866 int mlt_properties_parse( mlt_properties self, const char *namevalue )
868 if ( !self ) return 1;
869 char *name = strdup( namevalue );
872 char *ptr = strchr( name, '=' );
880 value = strdup( ptr );
885 value = strdup( ptr );
886 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
887 value[ strlen( value ) - 1 ] = '\0';
892 value = strdup( "" );
895 error = mlt_properties_set( self, name, value );
903 /** Get an integer associated to the name.
905 * \public \memberof mlt_properties_s
906 * \param self a properties list
907 * \param name the property to get
908 * \return The integer value, 0 if not found (which may also be a legitimate value)
911 int mlt_properties_get_int( mlt_properties self, const char *name )
914 mlt_property value = mlt_properties_find( self, name );
917 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
918 double fps = mlt_profile_fps( profile );
919 property_list *list = self->local;
920 result = mlt_property_get_int( value, fps, list->locale );
925 /** Set a property to an integer value.
927 * \public \memberof mlt_properties_s
928 * \param self a properties list
929 * \param name the property to set
930 * \param value the integer
931 * \return true if error
934 int mlt_properties_set_int( mlt_properties self, const char *name, int value )
938 if ( !self || !name ) return error;
940 // Fetch the property to work with
941 mlt_property property = mlt_properties_fetch( self, name );
943 // Set it if not NULL
944 if ( property != NULL )
946 error = mlt_property_set_int( property, value );
947 mlt_properties_do_mirror( self, name );
950 mlt_events_fire( self, "property-changed", name, NULL );
955 /** Get a 64-bit integer associated to the name.
957 * \public \memberof mlt_properties_s
958 * \param self a properties list
959 * \param name the property to get
960 * \return the integer value, 0 if not found (which may also be a legitimate value)
963 int64_t mlt_properties_get_int64( mlt_properties self, const char *name )
965 mlt_property value = mlt_properties_find( self, name );
966 return value == NULL ? 0 : mlt_property_get_int64( value );
969 /** Set a property to a 64-bit integer value.
971 * \public \memberof mlt_properties_s
972 * \param self a properties list
973 * \param name the property to set
974 * \param value the integer
975 * \return true if error
978 int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value )
982 if ( !self || !name ) return error;
984 // Fetch the property to work with
985 mlt_property property = mlt_properties_fetch( self, name );
987 // Set it if not NULL
988 if ( property != NULL )
990 error = mlt_property_set_int64( property, value );
991 mlt_properties_do_mirror( self, name );
994 mlt_events_fire( self, "property-changed", name, NULL );
999 /** Get a floating point value associated to the name.
1001 * \public \memberof mlt_properties_s
1002 * \param self a properties list
1003 * \param name the property to get
1004 * \return the floating point, 0 if not found (which may also be a legitimate value)
1007 double mlt_properties_get_double( mlt_properties self, const char *name )
1010 mlt_property value = mlt_properties_find( self, name );
1013 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1014 double fps = mlt_profile_fps( profile );
1015 property_list *list = self->local;
1016 result = mlt_property_get_double( value, fps, list->locale );
1021 /** Set a property to a floating point value.
1023 * \public \memberof mlt_properties_s
1024 * \param self a properties list
1025 * \param name the property to set
1026 * \param value the floating point value
1027 * \return true if error
1030 int mlt_properties_set_double( mlt_properties self, const char *name, double value )
1034 if ( !self || !name ) return error;
1036 // Fetch the property to work with
1037 mlt_property property = mlt_properties_fetch( self, name );
1039 // Set it if not NULL
1040 if ( property != NULL )
1042 error = mlt_property_set_double( property, value );
1043 mlt_properties_do_mirror( self, name );
1046 mlt_events_fire( self, "property-changed", name, NULL );
1051 /** Get a position value associated to the name.
1053 * \public \memberof mlt_properties_s
1054 * \param self a properties list
1055 * \param name the property to get
1056 * \return the position, 0 if not found (which may also be a legitimate value)
1059 mlt_position mlt_properties_get_position( mlt_properties self, const char *name )
1061 mlt_position result = 0;
1062 mlt_property value = mlt_properties_find( self, name );
1065 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1066 double fps = mlt_profile_fps( profile );
1067 property_list *list = self->local;
1068 result = mlt_property_get_position( value, fps, list->locale );
1073 /** Set a property to a position value.
1075 * \public \memberof mlt_properties_s
1076 * \param self a properties list
1077 * \param name the property to get
1078 * \param value the position
1079 * \return true if error
1082 int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value )
1086 if ( !self || !name ) return error;
1088 // Fetch the property to work with
1089 mlt_property property = mlt_properties_fetch( self, name );
1091 // Set it if not NULL
1092 if ( property != NULL )
1094 error = mlt_property_set_position( property, value );
1095 mlt_properties_do_mirror( self, name );
1098 mlt_events_fire( self, "property-changed", name, NULL );
1103 /** Get a binary data value associated to the name.
1105 * Do not free the returned pointer if you supplied a destructor function
1106 * when you set this property.
1107 * \public \memberof mlt_properties_s
1108 * \param self a properties list
1109 * \param name the property to get
1110 * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know)
1113 void *mlt_properties_get_data( mlt_properties self, const char *name, int *length )
1115 mlt_property value = mlt_properties_find( self, name );
1116 return value == NULL ? NULL : mlt_property_get_data( value, length );
1119 /** Store binary data as a property.
1121 * \public \memberof mlt_properties_s
1122 * \param self a properties list
1123 * \param name the property to set
1124 * \param value an opaque pointer to binary data
1125 * \param length the size of the binary data in bytes (optional)
1126 * \param destroy a function to deallocate the binary data when the property is closed (optional)
1127 * \param serialise a function that can serialize the binary data as text (optional)
1128 * \return true if error
1131 int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
1135 if ( !self || !name ) return error;
1137 // Fetch the property to work with
1138 mlt_property property = mlt_properties_fetch( self, name );
1140 // Set it if not NULL
1141 if ( property != NULL )
1142 error = mlt_property_set_data( property, value, length, destroy, serialise );
1144 mlt_events_fire( self, "property-changed", name, NULL );
1149 /** Rename a property.
1151 * \public \memberof mlt_properties_s
1152 * \param self a properties list
1153 * \param source the property to rename
1154 * \param dest the new name
1155 * \return true if the name is already in use
1158 int mlt_properties_rename( mlt_properties self, const char *source, const char *dest )
1160 mlt_property value = mlt_properties_find( self, dest );
1162 if ( value == NULL )
1164 property_list *list = self->local;
1168 mlt_properties_lock( self );
1169 for ( i = 0; i < list->count; i ++ )
1171 if ( !strcmp( list->name[ i ], source ) )
1173 free( list->name[ i ] );
1174 list->name[ i ] = strdup( dest );
1175 list->hash[ generate_hash( dest ) ] = i + 1;
1179 mlt_properties_unlock( self );
1182 return value != NULL;
1185 /** Dump the properties to a file handle.
1187 * \public \memberof mlt_properties_s
1188 * \param self a properties list
1189 * \param output a file handle
1192 void mlt_properties_dump( mlt_properties self, FILE *output )
1194 if ( !self || !output ) return;
1195 property_list *list = self->local;
1197 for ( i = 0; i < list->count; i ++ )
1198 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1199 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1202 /** Output the properties to a file handle.
1204 * This version includes reference counts and does not put each property on a new line.
1205 * \public \memberof mlt_properties_s
1206 * \param self a properties pointer
1207 * \param title a string to preface the output
1208 * \param output a file handle
1210 void mlt_properties_debug( mlt_properties self, const char *title, FILE *output )
1212 if ( !self || !output ) return;
1213 if ( output == NULL ) output = stderr;
1214 fprintf( output, "%s: ", title );
1217 property_list *list = self->local;
1219 fprintf( output, "[ ref=%d", list->ref_count );
1220 for ( i = 0; i < list->count; i ++ )
1221 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1222 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1224 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) );
1225 fprintf( output, " ]" );
1227 fprintf( output, "\n" );
1230 /** Save the properties to a file by name.
1232 * This uses the dump format - one line per property.
1233 * \public \memberof mlt_properties_s
1234 * \param self a properties list
1235 * \param filename the name of a file to create or overwrite
1236 * \return true if there was an error
1239 int mlt_properties_save( mlt_properties self, const char *filename )
1242 if ( !self || !filename ) return error;
1243 FILE *f = fopen( filename, "w" );
1246 mlt_properties_dump( self, f );
1253 /* This is a very basic cross platform fnmatch replacement - it will fail in
1254 * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
1257 /** Test whether a filename or pathname matches a shell-style pattern.
1259 * \private \memberof mlt_properties_s
1260 * \param wild a string containing a wildcard pattern
1261 * \param file the name of a file to test against
1262 * \return true if the file name matches the wildcard pattern
1265 static int mlt_fnmatch( const char *wild, const char *file )
1270 while( f < strlen( file ) && w < strlen( wild ) )
1272 if ( wild[ w ] == '*' )
1275 if ( w == strlen( wild ) )
1277 while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
1280 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
1285 else if ( wild[ 0 ] == '*' )
1295 return strlen( file ) == f && strlen( wild ) == w;
1298 /** Compare the string or serialized value of two properties.
1300 * \private \memberof mlt_properties_s
1301 * \param self a property
1302 * \param that a property
1303 * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that
1306 static int mlt_compare( const void *self, const void *that )
1308 return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) );
1311 /** Get the contents of a directory.
1313 * Obtains an optionally sorted list of the files found in a directory with a specific wild card.
1314 * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
1315 * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
1316 * \public \memberof mlt_properties_s
1317 * \param self a properties list
1318 * \param dirname the name of the directory
1319 * \param pattern a wildcard pattern to filter the directory listing
1320 * \param sort Do you want to sort the directory listing?
1321 * \return the number of items in the directory listing
1324 int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort )
1326 DIR *dir = opendir( dirname );
1331 struct dirent *de = readdir( dir );
1332 char fullname[ 1024 ];
1335 sprintf( key, "%d", mlt_properties_count( self ) );
1336 snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
1337 if ( pattern == NULL )
1338 mlt_properties_set( self, key, fullname );
1339 else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
1340 mlt_properties_set( self, key, fullname );
1341 de = readdir( dir );
1347 if ( sort && mlt_properties_count( self ) )
1349 property_list *list = self->local;
1350 mlt_properties_lock( self );
1351 qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare );
1352 mlt_properties_unlock( self );
1355 return mlt_properties_count( self );
1358 /** Close a properties object.
1360 * Deallocates the properties object and everything it contains.
1361 * \public \memberof mlt_properties_s
1362 * \param self a properties object
1365 void mlt_properties_close( mlt_properties self )
1367 if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 )
1369 if ( self->close != NULL )
1371 self->close( self->close_object );
1375 property_list *list = self->local;
1378 #if _MLT_PROPERTY_CHECKS_ == 1
1380 mlt_properties_debug( self, "Closing", stderr );
1383 #ifdef _MLT_PROPERTY_CHECKS_
1384 // Increment destroyed count
1385 properties_destroyed ++;
1387 // Show current stats - these should match when the app is closed
1388 mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
1391 // Clean up names and values
1392 for ( index = list->count - 1; index >= 0; index -- )
1394 mlt_property_close( list->value[ index ] );
1395 free( list->name[ index ] );
1398 #if defined(__linux__) || defined(__DARWIN__)
1401 freelocale( list->locale );
1404 // Clear up the list
1405 pthread_mutex_destroy( &list->mutex );
1407 free( list->value );
1410 // Free self now if self has no child
1411 if ( self->child == NULL )
1417 /** Determine if the properties list is really just a sequence or ordered list.
1419 * \public \memberof mlt_properties_s
1420 * \param properties a properties list
1421 * \return true if all of the property names are numeric (a sequence)
1424 int mlt_properties_is_sequence( mlt_properties properties )
1427 int n = mlt_properties_count( properties );
1428 for ( i = 0; i < n; i++ )
1429 if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) )
1434 /** \brief YAML Tiny Parser context structure
1436 * YAML is a nifty text format popular in the Ruby world as a cleaner,
1437 * less verbose alternative to XML. See this Wikipedia topic for an overview:
1438 * http://en.wikipedia.org/wiki/YAML
1439 * The YAML specification is at:
1441 * YAML::Tiny is a Perl module that specifies a subset of YAML that we are
1442 * using here (for the same reasons):
1443 * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm
1447 struct yaml_parser_context
1452 mlt_deque index_stack;
1455 unsigned int block_indent;
1458 typedef struct yaml_parser_context *yaml_parser;
1460 /** Remove spaces from the left side of a string.
1462 * \param s the string to trim
1463 * \return the number of characters removed
1466 static unsigned int ltrim( char **s )
1470 int n = strlen( c );
1471 for ( i = 0; i < n && *c == ' '; i++, c++ );
1476 /** Remove spaces from the right side of a string.
1478 * \param s the string to trim
1479 * \return the number of characters removed
1482 static unsigned int rtrim( char *s )
1484 int n = strlen( s );
1486 for ( i = n; i > 0 && s[i - 1] == ' '; --i )
1491 /** Parse a line of YAML Tiny.
1493 * Adds a property if needed.
1494 * \private \memberof yaml_parser_context
1495 * \param context a YAML Tiny Parser context
1496 * \param namevalue a line of YAML Tiny
1497 * \return true if there was an error
1500 static int parse_yaml( yaml_parser context, const char *namevalue )
1502 char *name_ = strdup( namevalue );
1506 char *ptr = strchr( name, ':' );
1507 unsigned int indent = ltrim( &name );
1508 mlt_properties properties = mlt_deque_peek_back( context->stack );
1510 // Ascending one more levels in the tree
1511 if ( indent < context->level )
1514 unsigned int n = ( context->level - indent ) / 2;
1515 for ( i = 0; i < n; i++ )
1517 mlt_deque_pop_back( context->stack );
1518 context->index = mlt_deque_pop_back_int( context->index_stack );
1520 properties = mlt_deque_peek_back( context->stack );
1521 context->level = indent;
1524 // Descending a level in the tree
1525 else if ( indent > context->level && context->block == 0 )
1527 context->level = indent;
1530 // If there is a colon that is not part of a block
1531 if ( ptr && ( indent == context->level ) )
1533 // Reset block processing
1534 if ( context->block_name )
1536 free( context->block_name );
1537 context->block_name = NULL;
1541 // Terminate the name and setup the value pointer
1545 char *comment = strchr( ptr, '#' );
1551 // Trim leading and trailing spaces from bare value
1555 // No value means a child
1556 if ( strcmp( ptr, "" ) == 0 )
1558 mlt_properties child = mlt_properties_new();
1559 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1560 mlt_properties_set_data( properties, name, child, 0,
1561 ( mlt_destructor )mlt_properties_close, NULL );
1562 mlt_deque_push_back( context->stack, child );
1563 mlt_deque_push_back_int( context->index_stack, context->index );
1569 // A dash indicates a sequence item
1570 if ( name[0] == '-' )
1572 mlt_properties child = mlt_properties_new();
1575 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1576 snprintf( key, sizeof(key), "%d", context->index++ );
1577 mlt_properties_set_data( properties, key, child, 0,
1578 ( mlt_destructor )mlt_properties_close, NULL );
1579 mlt_deque_push_back( context->stack, child );
1580 mlt_deque_push_back_int( context->index_stack, context->index );
1583 context->level += ltrim( &name ) + 1;
1591 value = strdup( ptr );
1592 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1593 value[ strlen( value ) - 1 ] = 0;
1596 // Value is folded or unfolded block
1597 else if ( *ptr == '|' || *ptr == '>' )
1599 context->block = *ptr;
1600 context->block_name = strdup( name );
1601 context->block_indent = 0;
1602 value = strdup( "" );
1608 value = strdup( ptr );
1612 // A list of scalars
1613 else if ( name[0] == '-' )
1615 // Reset block processing
1616 if ( context->block_name )
1618 free( context->block_name );
1619 context->block_name = NULL;
1625 snprintf( key, sizeof(key), "%d", context->index++ );
1629 char *comment = strchr( ptr, '#' );
1633 // Trim leading and trailing spaces from bare value
1641 value = strdup( ptr );
1642 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1643 value[ strlen( value ) - 1 ] = 0;
1646 // Value is folded or unfolded block
1647 else if ( *ptr == '|' || *ptr == '>' )
1649 context->block = *ptr;
1650 context->block_name = strdup( key );
1651 context->block_indent = 0;
1652 value = strdup( "" );
1658 value = strdup( ptr );
1662 name = name_ = strdup( key );
1666 else if ( context->block == '|' )
1668 if ( context->block_indent == 0 )
1669 context->block_indent = indent;
1670 if ( indent > context->block_indent )
1671 name = &name_[ context->block_indent ];
1673 char *old_value = mlt_properties_get( properties, context->block_name );
1674 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1675 strcpy( value, old_value );
1676 if ( strcmp( old_value, "" ) )
1677 strcat( value, "\n" );
1678 strcat( value, name );
1679 name = context->block_name;
1683 else if ( context->block == '>' )
1687 char *old_value = mlt_properties_get( properties, context->block_name );
1689 // Blank line (prepended with spaces) is new line
1690 if ( strcmp( name, "" ) == 0 )
1692 value = calloc( 1, strlen( old_value ) + 2 );
1693 strcat( value, old_value );
1694 strcat( value, "\n" );
1696 // Concatenate with space
1699 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1700 strcat( value, old_value );
1701 if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' )
1702 strcat( value, " " );
1703 strcat( value, name );
1705 name = context->block_name;
1710 value = strdup( "" );
1713 error = mlt_properties_set( properties, name, value );
1715 if ( !strcmp( name, "LC_NUMERIC" ) )
1716 mlt_properties_set_lcnumeric( properties, value );
1724 /** Parse a YAML Tiny file by name.
1726 * \public \memberof mlt_properties_s
1727 * \param filename the name of a text file containing YAML Tiny
1728 * \return a new properties list
1731 mlt_properties mlt_properties_parse_yaml( const char *filename )
1733 // Construct a standalone properties object
1734 mlt_properties self = mlt_properties_new( );
1739 FILE *file = fopen( filename, "r" );
1741 // Load contents of file
1746 char *ptemp = &temp[ 0 ];
1748 // Default to LC_NUMERIC = C
1749 mlt_properties_set_lcnumeric( self, "C" );
1752 yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) );
1753 context->stack = mlt_deque_init();
1754 context->index_stack = mlt_deque_init();
1755 mlt_deque_push_back( context->stack, self );
1756 mlt_deque_push_back_int( context->index_stack, 0 );
1758 // Read each string from the file
1759 while( fgets( temp, 1024, file ) )
1761 // Check for end-of-stream
1762 if ( strncmp( ptemp, "...", 3 ) == 0 )
1766 temp[ strlen( temp ) - 1 ] = '\0';
1768 // Skip blank lines, comment lines, and document separator
1769 if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 )
1770 && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) )
1771 parse_yaml( context, temp );
1776 mlt_deque_close( context->stack );
1777 mlt_deque_close( context->index_stack );
1778 if ( context->block_name )
1779 free( context->block_name );
1784 // Return the pointer
1789 * YAML Tiny Serializer
1792 /** How many bytes to grow at a time */
1793 #define STRBUF_GROWTH (1024)
1795 /** \brief Private to mlt_properties_s, a self-growing buffer for building strings
1805 typedef struct strbuf_s *strbuf;
1807 /** Create a new string buffer
1809 * \private \memberof strbuf_s
1810 * \return a new string buffer
1813 static strbuf strbuf_new( )
1815 strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) );
1816 buffer->size = STRBUF_GROWTH;
1817 buffer->string = calloc( 1, buffer->size );
1821 /** Destroy a string buffer
1823 * \private \memberof strbuf_s
1824 * \param buffer the string buffer to close
1827 static void strbuf_close( strbuf buffer )
1829 // We do not free buffer->string; strbuf user must save that pointer
1835 /** Format a string into a string buffer
1837 * A variable number of arguments follows the format string - one for each
1839 * \private \memberof strbuf_s
1840 * \param buffer the string buffer to write into
1841 * \param format a string that contains text and formatting instructions
1842 * \return the formatted string
1845 static char *strbuf_printf( strbuf buffer, const char *format, ... )
1847 while ( buffer->string )
1850 va_start( ap, format );
1851 size_t len = strlen( buffer->string );
1852 size_t remain = buffer->size - len - 1;
1853 int need = vsnprintf( buffer->string + len, remain, format, ap );
1855 if ( need > -1 && need < remain )
1857 buffer->string[ len ] = 0;
1858 buffer->size += need + STRBUF_GROWTH;
1859 buffer->string = realloc( buffer->string, buffer->size );
1861 return buffer->string;
1864 /** Indent a line of YAML Tiny.
1866 * \private \memberof strbuf_s
1867 * \param output a string buffer
1868 * \param indent the number of spaces to indent
1871 static inline void indent_yaml( strbuf output, int indent )
1874 for ( j = 0; j < indent; j++ )
1875 strbuf_printf( output, " " );
1878 static void strbuf_escape( strbuf output, const char *value, char c )
1880 char *v = strdup( value );
1882 char *found = strchr( s, c );
1887 strbuf_printf( output, "%s\\%c", s, c );
1889 found = strchr( s, c );
1891 strbuf_printf( output, "%s", s );
1895 /** Convert a line string into a YAML block literal.
1897 * \private \memberof strbuf_s
1898 * \param output a string buffer
1899 * \param value the string to format as a block literal
1900 * \param indent the number of spaces to indent
1903 static void output_yaml_block_literal( strbuf output, const char *value, int indent )
1905 char *v = strdup( value );
1907 char *eol = strchr( sol, '\n' );
1911 indent_yaml( output, indent );
1913 strbuf_printf( output, "%s\n", sol );
1915 eol = strchr( sol, '\n' );
1917 indent_yaml( output, indent );
1918 strbuf_printf( output, "%s\n", sol );
1922 /** Recursively serialize a properties list into a string buffer as YAML Tiny.
1924 * \private \memberof mlt_properties_s
1925 * \param self a properties list
1926 * \param output a string buffer to hold the serialized YAML Tiny
1927 * \param indent the number of spaces to indent (for recursion, initialize to 0)
1928 * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)?
1931 static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence )
1933 property_list *list = self->local;
1936 for ( i = 0; i < list->count; i ++ )
1938 // This implementation assumes that all data elements are property lists.
1939 // Unfortunately, we do not have run time type identification.
1940 mlt_properties child = mlt_property_get_data( list->value[ i ], NULL );
1942 if ( mlt_properties_is_sequence( self ) )
1944 // Ignore hidden/non-serialisable items
1945 if ( list->name[ i ][ 0 ] != '_' )
1947 // Indicate a sequence item
1948 indent_yaml( output, indent );
1949 strbuf_printf( output, "- " );
1951 // If the value can be represented as a string
1952 const char *value = mlt_properties_get( self, list->name[ i ] );
1953 if ( value && strcmp( value, "" ) )
1955 // Determine if this is an unfolded block literal
1956 if ( strchr( value, '\n' ) )
1958 strbuf_printf( output, "|\n" );
1959 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) );
1961 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1963 strbuf_printf( output, "\"" );
1964 strbuf_escape( output, value, '"' );
1965 strbuf_printf( output, "\"\n", value );
1969 strbuf_printf( output, "%s\n", value );
1975 serialise_yaml( child, output, indent + 2, 1 );
1979 // Assume this is a normal map-oriented properties list
1980 const char *value = mlt_properties_get( self, list->name[ i ] );
1982 // Ignore hidden/non-serialisable items
1983 // If the value can be represented as a string
1984 if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) )
1986 if ( is_parent_sequence == 0 )
1987 indent_yaml( output, indent );
1989 is_parent_sequence = 0;
1991 // Determine if this is an unfolded block literal
1992 if ( strchr( value, '\n' ) )
1994 strbuf_printf( output, "%s: |\n", list->name[ i ] );
1995 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) );
1997 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1999 strbuf_printf( output, "%s: \"", list->name[ i ] );
2000 strbuf_escape( output, value, '"' );
2001 strbuf_printf( output, "\"\n" );
2005 strbuf_printf( output, "%s: %s\n", list->name[ i ], value );
2009 // Output a child as a map item
2012 indent_yaml( output, indent );
2013 strbuf_printf( output, "%s:\n", list->name[ i ] );
2016 serialise_yaml( child, output, indent + 2, 0 );
2022 /** Serialize a properties list as a string of YAML Tiny.
2024 * The caller MUST free the returned string!
2025 * This operates on properties containing properties as a hierarchical data
2027 * \public \memberof mlt_properties_s
2028 * \param self a properties list
2029 * \return a string containing YAML Tiny that represents the properties list
2032 char *mlt_properties_serialise_yaml( mlt_properties self )
2034 if ( !self ) return NULL;
2035 const char *lc_numeric = mlt_properties_get_lcnumeric( self );
2036 strbuf b = strbuf_new();
2037 strbuf_printf( b, "---\n" );
2038 mlt_properties_set_lcnumeric( self, "C" );
2039 serialise_yaml( self, b, 0, 0 );
2040 mlt_properties_set_lcnumeric( self, lc_numeric );
2041 strbuf_printf( b, "...\n" );
2042 char *ret = b->string;
2047 /** Protect a properties list against concurrent access.
2049 * \public \memberof mlt_properties_s
2050 * \param self a properties list
2053 void mlt_properties_lock( mlt_properties self )
2056 pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex );
2059 /** End protecting a properties list against concurrent access.
2061 * \public \memberof mlt_properties_s
2062 * \param self a properties list
2065 void mlt_properties_unlock( mlt_properties self )
2068 pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex );
2071 /** Get a time string associated to the name.
2073 * Do not free the returned string. It's lifetime is controlled by the property.
2074 * \public \memberof mlt_properties_s
2075 * \param self a properties list
2076 * \param name the property to get
2077 * \param format the time format that you want
2078 * \return the property's time value or NULL if \p name does not exist or there is no profile
2081 char *mlt_properties_get_time( mlt_properties self, const char* name, mlt_time_format format )
2083 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2086 double fps = mlt_profile_fps( profile );
2087 mlt_property value = mlt_properties_find( self, name );
2088 property_list *list = self->local;
2089 return value == NULL ? NULL : mlt_property_get_time( value, format, fps, list->locale );
2094 /** Convert a frame count to a time string.
2096 * Do not free the returned string. It's lifetime is controlled by the property.
2097 * \public \memberof mlt_properties_s
2098 * \param self a properties list
2099 * \param frames the frame count to convert
2100 * \param format the time format that you want
2101 * \return the time string or NULL if error, e.g. there is no profile
2104 char *mlt_properties_frames_to_time( mlt_properties self, mlt_position frames, mlt_time_format format )
2106 const char *name = "_mlt_properties_time";
2107 mlt_properties_set_position( self, name, frames );
2108 return mlt_properties_get_time( self, name, format );
2111 /** Convert a time string to a frame count.
2113 * \public \memberof mlt_properties_s
2114 * \param self a properties list
2115 * \param time the time string to convert
2116 * \return a frame count or a negative value if error, e.g. there is no profile
2119 mlt_position mlt_properties_time_to_frames( mlt_properties self, const char *time )
2121 const char *name = "_mlt_properties_time";
2122 mlt_properties_set( self, name, time );
2123 return mlt_properties_get_position( self, name );
2126 /** Convert a numeric property to a tuple of color components.
2128 * If the property's string is red, green, blue, white, or black, then it
2129 * is converted to the corresponding opaque color tuple. Otherwise, the property
2130 * is fetched as an integer and then converted.
2131 * \public \memberof mlt_properties_s
2132 * \param self a properties list
2133 * \param name the property to get
2134 * \return a color structure
2137 mlt_color mlt_properties_get_color( mlt_properties self, const char* name )
2139 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2140 double fps = mlt_profile_fps( profile );
2141 property_list *list = self->local;
2142 mlt_property value = mlt_properties_find( self, name );
2143 mlt_color result = { 0xff, 0xff, 0xff, 0xff };
2146 const char *color = mlt_property_get_string_l( value, list->locale );
2147 unsigned int color_int = mlt_property_get_int( value, fps, list->locale );
2149 if ( !strcmp( color, "red" ) )
2155 else if ( !strcmp( color, "green" ) )
2161 else if ( !strcmp( color, "blue" ) )
2167 else if ( !strcmp( color, "black" ) )
2173 else if ( strcmp( color, "white" ) )
2175 result.r = ( color_int >> 24 ) & 0xff;
2176 result.g = ( color_int >> 16 ) & 0xff;
2177 result.b = ( color_int >> 8 ) & 0xff;
2178 result.a = ( color_int ) & 0xff;
2184 /** Set a property to an integer value by color.
2186 * \public \memberof mlt_properties_s
2187 * \param self a properties list
2188 * \param name the property to set
2189 * \param color the color
2190 * \return true if error
2193 int mlt_properties_set_color( mlt_properties self, const char *name, mlt_color color )
2197 if ( !self || !name ) return error;
2199 // Fetch the property to work with
2200 mlt_property property = mlt_properties_fetch( self, name );
2202 // Set it if not NULL
2203 if ( property != NULL )
2205 uint32_t value = ( color.r << 24 ) | ( color.g << 16 ) | ( color.b << 8 ) | color.a;
2206 error = mlt_property_set_int( property, value );
2207 mlt_properties_do_mirror( self, name );
2210 mlt_events_fire( self, "property-changed", name, NULL );
2215 /** Get a string value by name at a frame position.
2217 * Do not free the returned string. It's lifetime is controlled by the property
2218 * and this properties object.
2219 * \public \memberof mlt_properties_s
2220 * \param self a properties list
2221 * \param name the property to get
2222 * \param position the frame number
2223 * \param length the maximum number of frames when interpreting negative keyframe times,
2224 * <=0 if you don't care or need that
2225 * \return the property's string value or NULL if it does not exist
2228 char* mlt_properties_anim_get( mlt_properties self, const char *name, int position, int length )
2230 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2231 double fps = mlt_profile_fps( profile );
2232 mlt_property value = mlt_properties_find( self, name );
2233 property_list *list = self->local;
2234 return value == NULL ? NULL : mlt_property_anim_get_string( value, fps, list->locale, position, length );
2237 /** Set a property to a string at a frame position.
2239 * The event "property-changed" is fired after the property has been set.
2241 * This makes a copy of the string value you supply.
2242 * \public \memberof mlt_properties_s
2243 * \param self a properties list
2244 * \param name the property to set
2245 * \param value the property's new value
2246 * \param position the frame number
2247 * \param length the maximum number of frames when interpreting negative keyframe times,
2248 * <=0 if you don't care or need that
2249 * \return true if error
2252 int mlt_properties_anim_set( mlt_properties self, const char *name, const char *value, int position, int length )
2256 if ( !self || !name ) return error;
2258 // Fetch the property to work with
2259 mlt_property property = mlt_properties_fetch( self, name );
2261 // Set it if not NULL
2264 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2265 double fps = mlt_profile_fps( profile );
2266 property_list *list = self->local;
2267 error = mlt_property_anim_set_string( property, value,
2268 fps, list->locale, position, length );
2269 mlt_properties_do_mirror( self, name );
2272 mlt_events_fire( self, "property-changed", name, NULL );
2277 /** Get an integer associated to the name at a frame position.
2279 * \public \memberof mlt_properties_s
2280 * \param self a properties list
2281 * \param name the property to get
2282 * \param position the frame number
2283 * \param length the maximum number of frames when interpreting negative keyframe times,
2284 * <=0 if you don't care or need that
2285 * \return the integer value, 0 if not found (which may also be a legitimate value)
2288 int mlt_properties_anim_get_int( mlt_properties self, const char *name, int position, int length )
2290 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2291 double fps = mlt_profile_fps( profile );
2292 property_list *list = self->local;
2293 mlt_property value = mlt_properties_find( self, name );
2294 return value == NULL ? 0 : mlt_property_anim_get_int( value, fps, list->locale, position, length );
2297 /** Set a property to an integer value at a frame position.
2299 * \public \memberof mlt_properties_s
2300 * \param self a properties list
2301 * \param name the property to set
2302 * \param value the integer
2303 * \param position the frame number
2304 * \param length the maximum number of frames when interpreting negative keyframe times,
2305 * <=0 if you don't care or need that
2306 * \param keyframe_type the interpolation method for this keyframe
2307 * \return true if error
2310 int mlt_properties_anim_set_int( mlt_properties self, const char *name, int value,
2311 int position, int length, mlt_keyframe_type keyframe_type )
2315 if ( !self || !name ) return error;
2317 // Fetch the property to work with
2318 mlt_property property = mlt_properties_fetch( self, name );
2320 // Set it if not NULL
2321 if ( property != NULL )
2323 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2324 double fps = mlt_profile_fps( profile );
2325 property_list *list = self->local;
2326 error = mlt_property_anim_set_int( property, value, fps, list->locale, position, length, keyframe_type );
2327 mlt_properties_do_mirror( self, name );
2330 mlt_events_fire( self, "property-changed", name, NULL );
2335 /** Get a real number associated to the name at a frame position.
2337 * \public \memberof mlt_properties_s
2338 * \param self a properties list
2339 * \param name the property to get
2340 * \param position the frame number
2341 * \param length the maximum number of frames when interpreting negative keyframe times,
2342 * <=0 if you don't care or need that
2343 * \return the real number, 0 if not found (which may also be a legitimate value)
2346 double mlt_properties_anim_get_double( mlt_properties self, const char *name, int position, int length )
2348 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2349 double fps = mlt_profile_fps( profile );
2350 property_list *list = self->local;
2351 mlt_property value = mlt_properties_find( self, name );
2352 return value == NULL ? 0.0 : mlt_property_anim_get_double( value, fps, list->locale, position, length );
2355 /** Set a property to a real number at a frame position.
2357 * \public \memberof mlt_properties_s
2358 * \param self a properties list
2359 * \param name the property to set
2360 * \param value the real number
2361 * \param position the frame number
2362 * \param length the maximum number of frames when interpreting negative keyframe times,
2363 * <=0 if you don't care or need that
2364 * \param keyframe_type the interpolation method for this keyframe
2365 * \return true if error
2368 int mlt_properties_anim_set_double( mlt_properties self, const char *name, double value,
2369 int position, int length, mlt_keyframe_type keyframe_type )
2373 if ( !self || !name ) return error;
2375 // Fetch the property to work with
2376 mlt_property property = mlt_properties_fetch( self, name );
2378 // Set it if not NULL
2379 if ( property != NULL )
2381 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2382 double fps = mlt_profile_fps( profile );
2383 property_list *list = self->local;
2384 error = mlt_property_anim_set_double( property, value, fps, list->locale, position, length, keyframe_type );
2385 mlt_properties_do_mirror( self, name );
2388 mlt_events_fire( self, "property-changed", name, NULL );
2393 /** Get the animation associated to the name.
2395 * \public \memberof mlt_properties_s
2396 * \param self a properties list
2397 * \param name the property to get
2398 * \return The animation object or NULL if the property has no animation
2401 mlt_animation mlt_properties_get_animation( mlt_properties self, const char *name )
2403 mlt_property value = mlt_properties_find( self, name );
2404 return value == NULL ? NULL : mlt_property_get_animation( value );
2407 /** Set a property to a rectangle value.
2409 * \public \memberof mlt_properties_s
2410 * \param self a properties list
2411 * \param name the property to set
2412 * \param value the rectangle
2413 * \return true if error
2416 extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value )
2420 if ( !self || !name ) return error;
2422 // Fetch the property to work with
2423 mlt_property property = mlt_properties_fetch( self, name );
2425 // Set it if not NULL
2426 if ( property != NULL )
2428 error = mlt_property_set_rect( property, value );
2429 mlt_properties_do_mirror( self, name );
2432 mlt_events_fire( self, "property-changed", name, NULL );
2437 /** Get a rectangle associated to the name.
2439 * \public \memberof mlt_properties_s
2440 * \param self a properties list
2441 * \param name the property to get
2442 * \return the rectangle value, the rectangle fields will be DBL_MIN if not found
2445 extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char* name )
2447 property_list *list = self->local;
2448 mlt_property value = mlt_properties_find( self, name );
2449 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
2450 return value == NULL ? rect : mlt_property_get_rect( value, list->locale );
2453 /** Set a property to a rectangle value at a frame position.
2455 * \public \memberof mlt_properties_s
2456 * \param self a properties list
2457 * \param name the property to set
2458 * \param value the rectangle
2459 * \param position the frame number
2460 * \param length the maximum number of frames when interpreting negative keyframe times,
2461 * <=0 if you don't care or need that
2462 * \param keyframe_type the interpolation method for this keyframe
2463 * \return true if error
2466 extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_rect value,
2467 int position, int length , mlt_keyframe_type keyframe_type )
2471 if ( !self || !name ) return error;
2473 // Fetch the property to work with
2474 mlt_property property = mlt_properties_fetch( self, name );
2476 // Set it if not NULL
2477 if ( property != NULL )
2479 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2480 double fps = mlt_profile_fps( profile );
2481 property_list *list = self->local;
2482 error = mlt_property_anim_set_rect( property, value, fps, list->locale, position, length, keyframe_type );
2483 mlt_properties_do_mirror( self, name );
2486 mlt_events_fire( self, "property-changed", name, NULL );
2491 /** Get a rectangle associated to the name at a frame position.
2493 * \public \memberof mlt_properties_s
2494 * \param self a properties list
2495 * \param name the property to get
2496 * \param position the frame number
2497 * \param length the maximum number of frames when interpreting negative keyframe times,
2498 * <=0 if you don't care or need that
2499 * \return the rectangle value, the rectangle fields will be DBL_MIN if not found
2502 extern mlt_rect mlt_properties_anim_get_rect( mlt_properties self, const char *name, int position, int length )
2504 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2505 double fps = mlt_profile_fps( profile );
2506 property_list *list = self->local;
2507 mlt_property value = mlt_properties_find( self, name );
2508 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
2509 return value == NULL ? rect : mlt_property_anim_get_rect( value, fps, list->locale, position, length );