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 )
334 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
338 /** Copy a serializable property to a properties list that is mirroring this one.
340 * Special case - when a container (such as loader) is protecting another
341 * producer, we need to ensure that properties are passed through to the
343 * \private \memberof mlt_properties_s
344 * \param self a properties list
345 * \param name the name of the property to copy
348 static inline void mlt_properties_do_mirror( mlt_properties self, const char *name )
351 property_list *list = self->local;
352 if ( list->mirror != NULL )
354 char *value = mlt_properties_get( self, name );
356 mlt_properties_set( list->mirror, name, value );
360 /** Increment the reference count.
362 * \public \memberof mlt_properties_s
363 * \param self a properties list
364 * \return the new reference count
367 int mlt_properties_inc_ref( mlt_properties self )
372 property_list *list = self->local;
373 pthread_mutex_lock( &list->mutex );
374 result = ++ list->ref_count;
375 pthread_mutex_unlock( &list->mutex );
380 /** Decrement the reference count.
382 * \public \memberof mlt_properties_s
383 * \param self a properties list
384 * \return the new reference count
387 int mlt_properties_dec_ref( mlt_properties self )
392 property_list *list = self->local;
393 pthread_mutex_lock( &list->mutex );
394 result = -- list->ref_count;
395 pthread_mutex_unlock( &list->mutex );
400 /** Get the reference count.
402 * \public \memberof mlt_properties_s
403 * \param self a properties list
404 * \return the current reference count
407 int mlt_properties_ref_count( mlt_properties self )
411 property_list *list = self->local;
412 return list->ref_count;
417 /** Set a properties list to be a mirror copy of another.
419 * Note that this does not copy all existing properties. Rather, you must
420 * call this before setting the properties that you wish to copy.
421 * \public \memberof mlt_properties_s
422 * \param that the properties which will receive copies of the properties as they are set.
423 * \param self the properties to mirror
426 void mlt_properties_mirror( mlt_properties self, mlt_properties that )
429 property_list *list = self->local;
433 /** Copy all serializable properties to another properties list.
435 * \public \memberof mlt_properties_s
436 * \param self The properties to copy to
437 * \param that The properties to copy from
438 * \return true if error
441 int mlt_properties_inherit( mlt_properties self, mlt_properties that )
443 if ( !self || !that ) return 1;
444 int count = mlt_properties_count( that );
446 for ( i = 0; i < count; i ++ )
448 char *value = mlt_properties_get_value( that, i );
451 char *name = mlt_properties_get_name( that, i );
452 mlt_properties_set( self, name, value );
458 /** Pass all serializable properties that match a prefix to another properties object
460 * \warning The prefix is stripped from the name when it is set on the \p self properties list!
461 * For example a property named "foo.bar" will match prefix "foo.", but the property
462 * will be named simply "bar" on the receiving properties object.
463 * \public \memberof mlt_properties_s
464 * \param self the properties to copy to
465 * \param that The properties to copy from
466 * \param prefix the property names to match (required)
467 * \return true if error
470 int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix )
472 if ( !self || !that ) return 1;
473 int count = mlt_properties_count( that );
474 int length = strlen( prefix );
476 for ( i = 0; i < count; i ++ )
478 char *name = mlt_properties_get_name( that, i );
479 if ( !strncmp( name, prefix, length ) )
481 char *value = mlt_properties_get_value( that, i );
483 mlt_properties_set( self, name + length, value );
489 /** Locate a property by name.
491 * \private \memberof mlt_properties_s
492 * \param self a properties list
493 * \param name the property to lookup by name
494 * \return the property or NULL for failure
497 static inline mlt_property mlt_properties_find( mlt_properties self, const char *name )
499 if ( !self || !name ) return NULL;
500 property_list *list = self->local;
501 mlt_property value = NULL;
502 int key = generate_hash( name );
504 mlt_properties_lock( self );
506 int i = list->hash[ key ] - 1;
509 // Check if we're hashed
510 if ( list->count > 0 &&
511 name[ 0 ] == list->name[ i ][ 0 ] &&
512 !strcmp( list->name[ i ], name ) )
513 value = list->value[ i ];
516 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
517 if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
518 value = list->value[ i ];
520 mlt_properties_unlock( self );
525 /** Add a new property.
527 * \private \memberof mlt_properties_s
528 * \param self a properties list
529 * \param name the name of the new property
530 * \return the new property
533 static mlt_property mlt_properties_add( mlt_properties self, const char *name )
535 property_list *list = self->local;
536 int key = generate_hash( name );
539 mlt_properties_lock( self );
541 // Check that we have space and resize if necessary
542 if ( list->count == list->size )
545 list->name = realloc( list->name, list->size * sizeof( const char * ) );
546 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
549 // Assign name/value pair
550 list->name[ list->count ] = strdup( name );
551 list->value[ list->count ] = mlt_property_init( );
553 // Assign to hash table
554 if ( list->hash[ key ] == 0 )
555 list->hash[ key ] = list->count + 1;
557 // Return and increment count accordingly
558 result = list->value[ list->count ++ ];
560 mlt_properties_unlock( self );
565 /** Fetch a property by name and add one if not found.
567 * \private \memberof mlt_properties_s
568 * \param self a properties list
569 * \param name the property to lookup or add
570 * \return the property
573 static mlt_property mlt_properties_fetch( mlt_properties self, const char *name )
575 // Try to find an existing property first
576 mlt_property property = mlt_properties_find( self, name );
578 // If it wasn't found, create one
579 if ( property == NULL )
580 property = mlt_properties_add( self, name );
582 // Return the property
586 /** Copy a property to another properties list.
588 * \public \memberof mlt_properties_s
589 * \author Zach <zachary.drew@gmail.com>
590 * \param self the properties to copy to
591 * \param that the properties to copy from
592 * \param name the name of the property to copy
595 void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name )
597 // Make sure the source property isn't null.
598 mlt_property that_prop = mlt_properties_find( that, name );
599 if( that_prop == NULL )
602 mlt_property_pass( mlt_properties_fetch( self, name ), that_prop );
605 /** Copy all properties specified in a comma-separated list to another properties list.
607 * White space is also a delimiter.
608 * \public \memberof mlt_properties_s
609 * \author Zach <zachary.drew@gmail.com>
610 * \param self the properties to copy to
611 * \param that the properties to copy from
612 * \param list a delimited list of property names
613 * \return true if error
617 int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list )
619 if ( !self || !that || !list ) return 1;
620 char *props = strdup( list );
622 const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines
627 count = strcspn( ptr, delim );
629 if( ptr[count] == '\0' )
632 ptr[count] = '\0'; // Make it a real string
634 mlt_properties_pass_property( self, that, ptr );
638 ptr += strspn( ptr, delim );
647 /** Set a property to a string.
649 * The property name "properties" is reserved to load the preset in \p value.
650 * When the value begins with '@' then it is interpreted as a very simple math
651 * expression containing only the +, -, *, and / operators.
652 * The event "property-changed" is fired after the property has been set.
654 * This makes a copy of the string value you supply.
655 * \public \memberof mlt_properties_s
656 * \param self a properties list
657 * \param name the property to set
658 * \param value the property's new value
659 * \return true if error
662 int mlt_properties_set( mlt_properties self, const char *name, const char *value )
666 if ( !self || !name ) return error;
668 // Fetch the property to work with
669 mlt_property property = mlt_properties_fetch( self, name );
671 // Set it if not NULL
672 if ( property == NULL )
674 mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name );
676 else if ( value == NULL )
678 error = mlt_property_set_string( property, value );
679 mlt_properties_do_mirror( self, name );
681 else if ( *value != '@' )
683 error = mlt_property_set_string( property, value );
684 mlt_properties_do_mirror( self, name );
685 if ( !strcmp( name, "properties" ) )
686 mlt_properties_preset( self, value );
688 else if ( value[ 0 ] == '@' )
697 while ( *value != '\0' )
699 int length = strcspn( value, "+-*/" );
701 // Get the identifier
702 strncpy( id, value, length );
706 // Determine the value
707 if ( isdigit( id[ 0 ] ) )
709 #if defined(__GLIBC__) || defined(__DARWIN__)
710 property_list *list = self->local;
712 current = strtod_l( id, NULL, list->locale );
715 current = strtod( id, NULL );
719 current = mlt_properties_get_double( self, id );
722 // Apply the operation
735 total = total / current;
740 op = *value != '\0' ? *value ++ : ' ';
743 error = mlt_property_set_double( property, total );
744 mlt_properties_do_mirror( self, name );
747 mlt_events_fire( self, "property-changed", name, NULL );
752 /** Set or default a property to a string.
754 * This makes a copy of the string value you supply.
755 * \public \memberof mlt_properties_s
756 * \param self a properties list
757 * \param name the property to set
758 * \param value the string value to set or NULL to use the default
759 * \param def the default string if value is NULL
760 * \return true if error
763 int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def )
765 return mlt_properties_set( self, name, value == NULL ? def : value );
768 /** Get a string value by name.
770 * Do not free the returned string. It's lifetime is controlled by the property
771 * and this properties object.
772 * \public \memberof mlt_properties_s
773 * \param self a properties list
774 * \param name the property to get
775 * \return the property's string value or NULL if it does not exist
778 char *mlt_properties_get( mlt_properties self, const char *name )
781 mlt_property value = mlt_properties_find( self, name );
784 property_list *list = self->local;
785 result = mlt_property_get_string_l( value, list->locale );
790 /** Get a property name by index.
792 * Do not free the returned string.
793 * \public \memberof mlt_properties_s
794 * \param self a properties list
795 * \param index the numeric index of the property
796 * \return the name of the property or NULL if index is out of range
799 char *mlt_properties_get_name( mlt_properties self, int index )
801 if ( !self ) return NULL;
802 property_list *list = self->local;
803 if ( index >= 0 && index < list->count )
804 return list->name[ index ];
808 /** Get a property's string value by index.
810 * Do not free the returned string.
811 * \public \memberof mlt_properties_s
812 * \param self a properties list
813 * \param index the numeric index of the property
814 * \return the property value as a string or NULL if the index is out of range
817 char *mlt_properties_get_value( mlt_properties self, int index )
819 if ( !self ) return NULL;
820 property_list *list = self->local;
821 if ( index >= 0 && index < list->count )
822 return mlt_property_get_string_l( list->value[ index ], list->locale );
826 /** Get a data value by index.
828 * Do not free the returned pointer if you supplied a destructor function when you
830 * \public \memberof mlt_properties_s
831 * \param self a properties list
832 * \param index the numeric index of the property
833 * \param[out] size the size of the binary data in bytes or NULL if the index is out of range
836 void *mlt_properties_get_data_at( mlt_properties self, int index, int *size )
838 if ( !self ) return NULL;
839 property_list *list = self->local;
840 if ( index >= 0 && index < list->count )
841 return mlt_property_get_data( list->value[ index ], size );
845 /** Return the number of items in the list.
847 * \public \memberof mlt_properties_s
848 * \param self a properties list
849 * \return the number of property objects or -1 if error
852 int mlt_properties_count( mlt_properties self )
854 if ( !self ) return -1;
855 property_list *list = self->local;
859 /** Set a value by parsing a name=value string.
861 * \public \memberof mlt_properties_s
862 * \param self a properties list
863 * \param namevalue a string containing name and value delimited by '='
864 * \return true if there was an error
867 int mlt_properties_parse( mlt_properties self, const char *namevalue )
869 if ( !self ) return 1;
870 char *name = strdup( namevalue );
873 char *ptr = strchr( name, '=' );
881 value = strdup( ptr );
886 value = strdup( ptr );
887 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
888 value[ strlen( value ) - 1 ] = '\0';
893 value = strdup( "" );
896 error = mlt_properties_set( self, name, value );
904 /** Get an integer associated to the name.
906 * \public \memberof mlt_properties_s
907 * \param self a properties list
908 * \param name the property to get
909 * \return The integer value, 0 if not found (which may also be a legitimate value)
912 int mlt_properties_get_int( mlt_properties self, const char *name )
915 mlt_property value = mlt_properties_find( self, name );
918 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
919 double fps = mlt_profile_fps( profile );
920 property_list *list = self->local;
921 result = mlt_property_get_int( value, fps, list->locale );
926 /** Set a property to an integer value.
928 * \public \memberof mlt_properties_s
929 * \param self a properties list
930 * \param name the property to set
931 * \param value the integer
932 * \return true if error
935 int mlt_properties_set_int( mlt_properties self, const char *name, int value )
939 if ( !self || !name ) return error;
941 // Fetch the property to work with
942 mlt_property property = mlt_properties_fetch( self, name );
944 // Set it if not NULL
945 if ( property != NULL )
947 error = mlt_property_set_int( property, value );
948 mlt_properties_do_mirror( self, name );
951 mlt_events_fire( self, "property-changed", name, NULL );
956 /** Get a 64-bit integer associated to the name.
958 * \public \memberof mlt_properties_s
959 * \param self a properties list
960 * \param name the property to get
961 * \return the integer value, 0 if not found (which may also be a legitimate value)
964 int64_t mlt_properties_get_int64( mlt_properties self, const char *name )
966 mlt_property value = mlt_properties_find( self, name );
967 return value == NULL ? 0 : mlt_property_get_int64( value );
970 /** Set a property to a 64-bit integer value.
972 * \public \memberof mlt_properties_s
973 * \param self a properties list
974 * \param name the property to set
975 * \param value the integer
976 * \return true if error
979 int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value )
983 if ( !self || !name ) return error;
985 // Fetch the property to work with
986 mlt_property property = mlt_properties_fetch( self, name );
988 // Set it if not NULL
989 if ( property != NULL )
991 error = mlt_property_set_int64( property, value );
992 mlt_properties_do_mirror( self, name );
995 mlt_events_fire( self, "property-changed", name, NULL );
1000 /** Get a floating point value associated to the name.
1002 * \public \memberof mlt_properties_s
1003 * \param self a properties list
1004 * \param name the property to get
1005 * \return the floating point, 0 if not found (which may also be a legitimate value)
1008 double mlt_properties_get_double( mlt_properties self, const char *name )
1011 mlt_property value = mlt_properties_find( self, name );
1014 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1015 double fps = mlt_profile_fps( profile );
1016 property_list *list = self->local;
1017 result = mlt_property_get_double( value, fps, list->locale );
1022 /** Set a property to a floating point value.
1024 * \public \memberof mlt_properties_s
1025 * \param self a properties list
1026 * \param name the property to set
1027 * \param value the floating point value
1028 * \return true if error
1031 int mlt_properties_set_double( mlt_properties self, const char *name, double value )
1035 if ( !self || !name ) return error;
1037 // Fetch the property to work with
1038 mlt_property property = mlt_properties_fetch( self, name );
1040 // Set it if not NULL
1041 if ( property != NULL )
1043 error = mlt_property_set_double( property, value );
1044 mlt_properties_do_mirror( self, name );
1047 mlt_events_fire( self, "property-changed", name, NULL );
1052 /** Get a position value associated to the name.
1054 * \public \memberof mlt_properties_s
1055 * \param self a properties list
1056 * \param name the property to get
1057 * \return the position, 0 if not found (which may also be a legitimate value)
1060 mlt_position mlt_properties_get_position( mlt_properties self, const char *name )
1062 mlt_position result = 0;
1063 mlt_property value = mlt_properties_find( self, name );
1066 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1067 double fps = mlt_profile_fps( profile );
1068 property_list *list = self->local;
1069 result = mlt_property_get_position( value, fps, list->locale );
1074 /** Set a property to a position value.
1076 * \public \memberof mlt_properties_s
1077 * \param self a properties list
1078 * \param name the property to get
1079 * \param value the position
1080 * \return true if error
1083 int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value )
1087 if ( !self || !name ) return error;
1089 // Fetch the property to work with
1090 mlt_property property = mlt_properties_fetch( self, name );
1092 // Set it if not NULL
1093 if ( property != NULL )
1095 error = mlt_property_set_position( property, value );
1096 mlt_properties_do_mirror( self, name );
1099 mlt_events_fire( self, "property-changed", name, NULL );
1104 /** Get a binary data value associated to the name.
1106 * Do not free the returned pointer if you supplied a destructor function
1107 * when you set this property.
1108 * \public \memberof mlt_properties_s
1109 * \param self a properties list
1110 * \param name the property to get
1111 * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know)
1114 void *mlt_properties_get_data( mlt_properties self, const char *name, int *length )
1116 mlt_property value = mlt_properties_find( self, name );
1117 return value == NULL ? NULL : mlt_property_get_data( value, length );
1120 /** Store binary data as a property.
1122 * \public \memberof mlt_properties_s
1123 * \param self a properties list
1124 * \param name the property to set
1125 * \param value an opaque pointer to binary data
1126 * \param length the size of the binary data in bytes (optional)
1127 * \param destroy a function to deallocate the binary data when the property is closed (optional)
1128 * \param serialise a function that can serialize the binary data as text (optional)
1129 * \return true if error
1132 int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
1136 if ( !self || !name ) return error;
1138 // Fetch the property to work with
1139 mlt_property property = mlt_properties_fetch( self, name );
1141 // Set it if not NULL
1142 if ( property != NULL )
1143 error = mlt_property_set_data( property, value, length, destroy, serialise );
1145 mlt_events_fire( self, "property-changed", name, NULL );
1150 /** Rename a property.
1152 * \public \memberof mlt_properties_s
1153 * \param self a properties list
1154 * \param source the property to rename
1155 * \param dest the new name
1156 * \return true if the name is already in use
1159 int mlt_properties_rename( mlt_properties self, const char *source, const char *dest )
1161 mlt_property value = mlt_properties_find( self, dest );
1163 if ( value == NULL )
1165 property_list *list = self->local;
1169 mlt_properties_lock( self );
1170 for ( i = 0; i < list->count; i ++ )
1172 if ( !strcmp( list->name[ i ], source ) )
1174 free( list->name[ i ] );
1175 list->name[ i ] = strdup( dest );
1176 list->hash[ generate_hash( dest ) ] = i + 1;
1180 mlt_properties_unlock( self );
1183 return value != NULL;
1186 /** Dump the properties to a file handle.
1188 * \public \memberof mlt_properties_s
1189 * \param self a properties list
1190 * \param output a file handle
1193 void mlt_properties_dump( mlt_properties self, FILE *output )
1195 if ( !self || !output ) return;
1196 property_list *list = self->local;
1198 for ( i = 0; i < list->count; i ++ )
1199 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1200 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1203 /** Output the properties to a file handle.
1205 * This version includes reference counts and does not put each property on a new line.
1206 * \public \memberof mlt_properties_s
1207 * \param self a properties pointer
1208 * \param title a string to preface the output
1209 * \param output a file handle
1211 void mlt_properties_debug( mlt_properties self, const char *title, FILE *output )
1213 if ( !self || !output ) return;
1214 if ( output == NULL ) output = stderr;
1215 fprintf( output, "%s: ", title );
1218 property_list *list = self->local;
1220 fprintf( output, "[ ref=%d", list->ref_count );
1221 for ( i = 0; i < list->count; i ++ )
1222 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1223 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1225 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) );
1226 fprintf( output, " ]" );
1228 fprintf( output, "\n" );
1231 /** Save the properties to a file by name.
1233 * This uses the dump format - one line per property.
1234 * \public \memberof mlt_properties_s
1235 * \param self a properties list
1236 * \param filename the name of a file to create or overwrite
1237 * \return true if there was an error
1240 int mlt_properties_save( mlt_properties self, const char *filename )
1243 if ( !self || !filename ) return error;
1244 FILE *f = fopen( filename, "w" );
1247 mlt_properties_dump( self, f );
1254 /* This is a very basic cross platform fnmatch replacement - it will fail in
1255 * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
1258 /** Test whether a filename or pathname matches a shell-style pattern.
1260 * \private \memberof mlt_properties_s
1261 * \param wild a string containing a wildcard pattern
1262 * \param file the name of a file to test against
1263 * \return true if the file name matches the wildcard pattern
1266 static int mlt_fnmatch( const char *wild, const char *file )
1271 while( f < strlen( file ) && w < strlen( wild ) )
1273 if ( wild[ w ] == '*' )
1276 if ( w == strlen( wild ) )
1278 while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
1281 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
1286 else if ( wild[ 0 ] == '*' )
1296 return strlen( file ) == f && strlen( wild ) == w;
1299 /** Compare the string or serialized value of two properties.
1301 * \private \memberof mlt_properties_s
1302 * \param self a property
1303 * \param that a property
1304 * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that
1307 static int mlt_compare( const void *self, const void *that )
1309 return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) );
1312 /** Get the contents of a directory.
1314 * Obtains an optionally sorted list of the files found in a directory with a specific wild card.
1315 * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
1316 * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
1317 * \public \memberof mlt_properties_s
1318 * \param self a properties list
1319 * \param dirname the name of the directory
1320 * \param pattern a wildcard pattern to filter the directory listing
1321 * \param sort Do you want to sort the directory listing?
1322 * \return the number of items in the directory listing
1325 int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort )
1327 DIR *dir = opendir( dirname );
1332 struct dirent *de = readdir( dir );
1333 char fullname[ 1024 ];
1336 sprintf( key, "%d", mlt_properties_count( self ) );
1337 snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
1338 if ( pattern == NULL )
1339 mlt_properties_set( self, key, fullname );
1340 else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
1341 mlt_properties_set( self, key, fullname );
1342 de = readdir( dir );
1348 if ( sort && mlt_properties_count( self ) )
1350 property_list *list = self->local;
1351 mlt_properties_lock( self );
1352 qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare );
1353 mlt_properties_unlock( self );
1356 return mlt_properties_count( self );
1359 /** Close a properties object.
1361 * Deallocates the properties object and everything it contains.
1362 * \public \memberof mlt_properties_s
1363 * \param self a properties object
1366 void mlt_properties_close( mlt_properties self )
1368 if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 )
1370 if ( self->close != NULL )
1372 self->close( self->close_object );
1376 property_list *list = self->local;
1379 #if _MLT_PROPERTY_CHECKS_ == 1
1381 mlt_properties_debug( self, "Closing", stderr );
1384 #ifdef _MLT_PROPERTY_CHECKS_
1385 // Increment destroyed count
1386 properties_destroyed ++;
1388 // Show current stats - these should match when the app is closed
1389 mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
1392 // Clean up names and values
1393 for ( index = list->count - 1; index >= 0; index -- )
1395 mlt_property_close( list->value[ index ] );
1396 free( list->name[ index ] );
1399 #if defined(__linux__) || defined(__DARWIN__)
1402 freelocale( list->locale );
1405 // Clear up the list
1406 pthread_mutex_destroy( &list->mutex );
1408 free( list->value );
1411 // Free self now if self has no child
1412 if ( self->child == NULL )
1418 /** Determine if the properties list is really just a sequence or ordered list.
1420 * \public \memberof mlt_properties_s
1421 * \param properties a properties list
1422 * \return true if all of the property names are numeric (a sequence)
1425 int mlt_properties_is_sequence( mlt_properties properties )
1428 int n = mlt_properties_count( properties );
1429 for ( i = 0; i < n; i++ )
1430 if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) )
1435 /** \brief YAML Tiny Parser context structure
1437 * YAML is a nifty text format popular in the Ruby world as a cleaner,
1438 * less verbose alternative to XML. See this Wikipedia topic for an overview:
1439 * http://en.wikipedia.org/wiki/YAML
1440 * The YAML specification is at:
1442 * YAML::Tiny is a Perl module that specifies a subset of YAML that we are
1443 * using here (for the same reasons):
1444 * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm
1448 struct yaml_parser_context
1453 mlt_deque index_stack;
1456 unsigned int block_indent;
1459 typedef struct yaml_parser_context *yaml_parser;
1461 /** Remove spaces from the left side of a string.
1463 * \param s the string to trim
1464 * \return the number of characters removed
1467 static unsigned int ltrim( char **s )
1471 int n = strlen( c );
1472 for ( i = 0; i < n && *c == ' '; i++, c++ );
1477 /** Remove spaces from the right side of a string.
1479 * \param s the string to trim
1480 * \return the number of characters removed
1483 static unsigned int rtrim( char *s )
1485 int n = strlen( s );
1487 for ( i = n; i > 0 && s[i - 1] == ' '; --i )
1492 /** Parse a line of YAML Tiny.
1494 * Adds a property if needed.
1495 * \private \memberof yaml_parser_context
1496 * \param context a YAML Tiny Parser context
1497 * \param namevalue a line of YAML Tiny
1498 * \return true if there was an error
1501 static int parse_yaml( yaml_parser context, const char *namevalue )
1503 char *name_ = strdup( namevalue );
1507 char *ptr = strchr( name, ':' );
1508 unsigned int indent = ltrim( &name );
1509 mlt_properties properties = mlt_deque_peek_back( context->stack );
1511 // Ascending one more levels in the tree
1512 if ( indent < context->level )
1515 unsigned int n = ( context->level - indent ) / 2;
1516 for ( i = 0; i < n; i++ )
1518 mlt_deque_pop_back( context->stack );
1519 context->index = mlt_deque_pop_back_int( context->index_stack );
1521 properties = mlt_deque_peek_back( context->stack );
1522 context->level = indent;
1525 // Descending a level in the tree
1526 else if ( indent > context->level && context->block == 0 )
1528 context->level = indent;
1531 // If there is a colon that is not part of a block
1532 if ( ptr && ( indent == context->level ) )
1534 // Reset block processing
1535 if ( context->block_name )
1537 free( context->block_name );
1538 context->block_name = NULL;
1542 // Terminate the name and setup the value pointer
1546 char *comment = strchr( ptr, '#' );
1552 // Trim leading and trailing spaces from bare value
1556 // No value means a child
1557 if ( strcmp( ptr, "" ) == 0 )
1559 mlt_properties child = mlt_properties_new();
1560 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1561 mlt_properties_set_data( properties, name, child, 0,
1562 ( mlt_destructor )mlt_properties_close, NULL );
1563 mlt_deque_push_back( context->stack, child );
1564 mlt_deque_push_back_int( context->index_stack, context->index );
1570 // A dash indicates a sequence item
1571 if ( name[0] == '-' )
1573 mlt_properties child = mlt_properties_new();
1576 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1577 snprintf( key, sizeof(key), "%d", context->index++ );
1578 mlt_properties_set_data( properties, key, child, 0,
1579 ( mlt_destructor )mlt_properties_close, NULL );
1580 mlt_deque_push_back( context->stack, child );
1581 mlt_deque_push_back_int( context->index_stack, context->index );
1584 context->level += ltrim( &name ) + 1;
1592 value = strdup( ptr );
1593 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1594 value[ strlen( value ) - 1 ] = 0;
1597 // Value is folded or unfolded block
1598 else if ( *ptr == '|' || *ptr == '>' )
1600 context->block = *ptr;
1601 context->block_name = strdup( name );
1602 context->block_indent = 0;
1603 value = strdup( "" );
1609 value = strdup( ptr );
1613 // A list of scalars
1614 else if ( name[0] == '-' )
1616 // Reset block processing
1617 if ( context->block_name )
1619 free( context->block_name );
1620 context->block_name = NULL;
1626 snprintf( key, sizeof(key), "%d", context->index++ );
1630 char *comment = strchr( ptr, '#' );
1634 // Trim leading and trailing spaces from bare value
1642 value = strdup( ptr );
1643 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1644 value[ strlen( value ) - 1 ] = 0;
1647 // Value is folded or unfolded block
1648 else if ( *ptr == '|' || *ptr == '>' )
1650 context->block = *ptr;
1651 context->block_name = strdup( key );
1652 context->block_indent = 0;
1653 value = strdup( "" );
1659 value = strdup( ptr );
1663 name = name_ = strdup( key );
1667 else if ( context->block == '|' )
1669 if ( context->block_indent == 0 )
1670 context->block_indent = indent;
1671 if ( indent > context->block_indent )
1672 name = &name_[ context->block_indent ];
1674 char *old_value = mlt_properties_get( properties, context->block_name );
1675 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1676 strcpy( value, old_value );
1677 if ( strcmp( old_value, "" ) )
1678 strcat( value, "\n" );
1679 strcat( value, name );
1680 name = context->block_name;
1684 else if ( context->block == '>' )
1688 char *old_value = mlt_properties_get( properties, context->block_name );
1690 // Blank line (prepended with spaces) is new line
1691 if ( strcmp( name, "" ) == 0 )
1693 value = calloc( 1, strlen( old_value ) + 2 );
1694 strcat( value, old_value );
1695 strcat( value, "\n" );
1697 // Concatenate with space
1700 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1701 strcat( value, old_value );
1702 if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' )
1703 strcat( value, " " );
1704 strcat( value, name );
1706 name = context->block_name;
1711 value = strdup( "" );
1714 error = mlt_properties_set( properties, name, value );
1716 if ( !strcmp( name, "LC_NUMERIC" ) )
1717 mlt_properties_set_lcnumeric( properties, value );
1725 /** Parse a YAML Tiny file by name.
1727 * \public \memberof mlt_properties_s
1728 * \param filename the name of a text file containing YAML Tiny
1729 * \return a new properties list
1732 mlt_properties mlt_properties_parse_yaml( const char *filename )
1734 // Construct a standalone properties object
1735 mlt_properties self = mlt_properties_new( );
1740 FILE *file = fopen( filename, "r" );
1742 // Load contents of file
1747 char *ptemp = &temp[ 0 ];
1749 // Default to LC_NUMERIC = C
1750 mlt_properties_set_lcnumeric( self, "C" );
1753 yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) );
1754 context->stack = mlt_deque_init();
1755 context->index_stack = mlt_deque_init();
1756 mlt_deque_push_back( context->stack, self );
1757 mlt_deque_push_back_int( context->index_stack, 0 );
1759 // Read each string from the file
1760 while( fgets( temp, 1024, file ) )
1762 // Check for end-of-stream
1763 if ( strncmp( ptemp, "...", 3 ) == 0 )
1767 temp[ strlen( temp ) - 1 ] = '\0';
1769 // Skip blank lines, comment lines, and document separator
1770 if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 )
1771 && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) )
1772 parse_yaml( context, temp );
1777 mlt_deque_close( context->stack );
1778 mlt_deque_close( context->index_stack );
1779 if ( context->block_name )
1780 free( context->block_name );
1785 // Return the pointer
1790 * YAML Tiny Serializer
1793 /** How many bytes to grow at a time */
1794 #define STRBUF_GROWTH (1024)
1796 /** \brief Private to mlt_properties_s, a self-growing buffer for building strings
1806 typedef struct strbuf_s *strbuf;
1808 /** Create a new string buffer
1810 * \private \memberof strbuf_s
1811 * \return a new string buffer
1814 static strbuf strbuf_new( )
1816 strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) );
1817 buffer->size = STRBUF_GROWTH;
1818 buffer->string = calloc( 1, buffer->size );
1822 /** Destroy a string buffer
1824 * \private \memberof strbuf_s
1825 * \param buffer the string buffer to close
1828 static void strbuf_close( strbuf buffer )
1830 // We do not free buffer->string; strbuf user must save that pointer
1836 /** Format a string into a string buffer
1838 * A variable number of arguments follows the format string - one for each
1840 * \private \memberof strbuf_s
1841 * \param buffer the string buffer to write into
1842 * \param format a string that contains text and formatting instructions
1843 * \return the formatted string
1846 static char *strbuf_printf( strbuf buffer, const char *format, ... )
1848 while ( buffer->string )
1851 va_start( ap, format );
1852 size_t len = strlen( buffer->string );
1853 size_t remain = buffer->size - len - 1;
1854 int need = vsnprintf( buffer->string + len, remain, format, ap );
1856 if ( need > -1 && need < remain )
1858 buffer->string[ len ] = 0;
1859 buffer->size += need + STRBUF_GROWTH;
1860 buffer->string = realloc( buffer->string, buffer->size );
1862 return buffer->string;
1865 /** Indent a line of YAML Tiny.
1867 * \private \memberof strbuf_s
1868 * \param output a string buffer
1869 * \param indent the number of spaces to indent
1872 static inline void indent_yaml( strbuf output, int indent )
1875 for ( j = 0; j < indent; j++ )
1876 strbuf_printf( output, " " );
1879 static void strbuf_escape( strbuf output, const char *value, char c )
1881 char *v = strdup( value );
1883 char *found = strchr( s, c );
1888 strbuf_printf( output, "%s\\%c", s, c );
1890 found = strchr( s, c );
1892 strbuf_printf( output, "%s", s );
1896 /** Convert a line string into a YAML block literal.
1898 * \private \memberof strbuf_s
1899 * \param output a string buffer
1900 * \param value the string to format as a block literal
1901 * \param indent the number of spaces to indent
1904 static void output_yaml_block_literal( strbuf output, const char *value, int indent )
1906 char *v = strdup( value );
1908 char *eol = strchr( sol, '\n' );
1912 indent_yaml( output, indent );
1914 strbuf_printf( output, "%s\n", sol );
1916 eol = strchr( sol, '\n' );
1918 indent_yaml( output, indent );
1919 strbuf_printf( output, "%s\n", sol );
1923 /** Recursively serialize a properties list into a string buffer as YAML Tiny.
1925 * \private \memberof mlt_properties_s
1926 * \param self a properties list
1927 * \param output a string buffer to hold the serialized YAML Tiny
1928 * \param indent the number of spaces to indent (for recursion, initialize to 0)
1929 * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)?
1932 static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence )
1934 property_list *list = self->local;
1937 for ( i = 0; i < list->count; i ++ )
1939 // This implementation assumes that all data elements are property lists.
1940 // Unfortunately, we do not have run time type identification.
1941 mlt_properties child = mlt_property_get_data( list->value[ i ], NULL );
1943 if ( mlt_properties_is_sequence( self ) )
1945 // Ignore hidden/non-serialisable items
1946 if ( list->name[ i ][ 0 ] != '_' )
1948 // Indicate a sequence item
1949 indent_yaml( output, indent );
1950 strbuf_printf( output, "- " );
1952 // If the value can be represented as a string
1953 const char *value = mlt_properties_get( self, list->name[ i ] );
1954 if ( value && strcmp( value, "" ) )
1956 // Determine if this is an unfolded block literal
1957 if ( strchr( value, '\n' ) )
1959 strbuf_printf( output, "|\n" );
1960 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) );
1962 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1964 strbuf_printf( output, "\"" );
1965 strbuf_escape( output, value, '"' );
1966 strbuf_printf( output, "\"\n", value );
1970 strbuf_printf( output, "%s\n", value );
1976 serialise_yaml( child, output, indent + 2, 1 );
1980 // Assume this is a normal map-oriented properties list
1981 const char *value = mlt_properties_get( self, list->name[ i ] );
1983 // Ignore hidden/non-serialisable items
1984 // If the value can be represented as a string
1985 if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) )
1987 if ( is_parent_sequence == 0 )
1988 indent_yaml( output, indent );
1990 is_parent_sequence = 0;
1992 // Determine if this is an unfolded block literal
1993 if ( strchr( value, '\n' ) )
1995 strbuf_printf( output, "%s: |\n", list->name[ i ] );
1996 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) );
1998 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
2000 strbuf_printf( output, "%s: \"", list->name[ i ] );
2001 strbuf_escape( output, value, '"' );
2002 strbuf_printf( output, "\"\n" );
2006 strbuf_printf( output, "%s: %s\n", list->name[ i ], value );
2010 // Output a child as a map item
2013 indent_yaml( output, indent );
2014 strbuf_printf( output, "%s:\n", list->name[ i ] );
2017 serialise_yaml( child, output, indent + 2, 0 );
2023 /** Serialize a properties list as a string of YAML Tiny.
2025 * The caller MUST free the returned string!
2026 * This operates on properties containing properties as a hierarchical data
2028 * \public \memberof mlt_properties_s
2029 * \param self a properties list
2030 * \return a string containing YAML Tiny that represents the properties list
2033 char *mlt_properties_serialise_yaml( mlt_properties self )
2035 if ( !self ) return NULL;
2036 const char *lc_numeric = mlt_properties_get_lcnumeric( self );
2037 strbuf b = strbuf_new();
2038 strbuf_printf( b, "---\n" );
2039 mlt_properties_set_lcnumeric( self, "C" );
2040 serialise_yaml( self, b, 0, 0 );
2041 mlt_properties_set_lcnumeric( self, lc_numeric );
2042 strbuf_printf( b, "...\n" );
2043 char *ret = b->string;
2048 /** Protect a properties list against concurrent access.
2050 * \public \memberof mlt_properties_s
2051 * \param self a properties list
2054 void mlt_properties_lock( mlt_properties self )
2057 pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex );
2060 /** End protecting a properties list against concurrent access.
2062 * \public \memberof mlt_properties_s
2063 * \param self a properties list
2066 void mlt_properties_unlock( mlt_properties self )
2069 pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex );
2072 /** Get a time string associated to the name.
2074 * Do not free the returned string. It's lifetime is controlled by the property.
2075 * \public \memberof mlt_properties_s
2076 * \param self a properties list
2077 * \param name the property to get
2078 * \param format the time format that you want
2079 * \return the property's time value or NULL if \p name does not exist or there is no profile
2082 char *mlt_properties_get_time( mlt_properties self, const char* name, mlt_time_format format )
2084 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2087 double fps = mlt_profile_fps( profile );
2088 mlt_property value = mlt_properties_find( self, name );
2089 property_list *list = self->local;
2090 return value == NULL ? NULL : mlt_property_get_time( value, format, fps, list->locale );
2095 /** Convert a numeric property to a tuple of color components.
2097 * If the property's string is red, green, blue, white, or black, then it
2098 * is converted to the corresponding opaque color tuple. Otherwise, the property
2099 * is fetched as an integer and then converted.
2100 * \public \memberof mlt_properties_s
2101 * \param self a properties list
2102 * \param name the property to get
2103 * \return a color structure
2106 mlt_color mlt_properties_get_color( mlt_properties self, const char* name )
2108 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2109 double fps = mlt_profile_fps( profile );
2110 property_list *list = self->local;
2111 mlt_property value = mlt_properties_find( self, name );
2112 mlt_color result = { 0xff, 0xff, 0xff, 0xff };
2115 const char *color = mlt_property_get_string_l( value, list->locale );
2116 unsigned int color_int = mlt_property_get_int( value, fps, list->locale );
2118 if ( !strcmp( color, "red" ) )
2124 else if ( !strcmp( color, "green" ) )
2130 else if ( !strcmp( color, "blue" ) )
2136 else if ( !strcmp( color, "black" ) )
2142 else if ( strcmp( color, "white" ) )
2144 result.r = ( color_int >> 24 ) & 0xff;
2145 result.g = ( color_int >> 16 ) & 0xff;
2146 result.b = ( color_int >> 8 ) & 0xff;
2147 result.a = ( color_int ) & 0xff;
2153 /** Set a property to an integer value by color.
2155 * \public \memberof mlt_properties_s
2156 * \param self a properties list
2157 * \param name the property to set
2158 * \param color the color
2159 * \return true if error
2162 int mlt_properties_set_color( mlt_properties self, const char *name, mlt_color color )
2166 if ( !self || !name ) return error;
2168 // Fetch the property to work with
2169 mlt_property property = mlt_properties_fetch( self, name );
2171 // Set it if not NULL
2172 if ( property != NULL )
2174 uint32_t value = ( color.r << 24 ) | ( color.g << 16 ) | ( color.b << 8 ) | color.a;
2175 error = mlt_property_set_int( property, value );
2176 mlt_properties_do_mirror( self, name );
2179 mlt_events_fire( self, "property-changed", name, NULL );
2184 /** Get a string value by name at a frame position.
2186 * Do not free the returned string. It's lifetime is controlled by the property
2187 * and this properties object.
2188 * \public \memberof mlt_properties_s
2189 * \param self a properties list
2190 * \param name the property to get
2191 * \param position the frame number
2192 * \param length the maximum number of frames when interpreting negative keyframe times,
2193 * <=0 if you don't care or need that
2194 * \return the property's string value or NULL if it does not exist
2197 char* mlt_properties_anim_get( mlt_properties self, const char *name, int position, int length )
2199 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2200 double fps = mlt_profile_fps( profile );
2201 mlt_property value = mlt_properties_find( self, name );
2202 property_list *list = self->local;
2203 return value == NULL ? NULL : mlt_property_anim_get_string( value, fps, list->locale, position, length );
2206 /** Set a property to a string at a frame position.
2208 * The event "property-changed" is fired after the property has been set.
2210 * This makes a copy of the string value you supply.
2211 * \public \memberof mlt_properties_s
2212 * \param self a properties list
2213 * \param name the property to set
2214 * \param value the property's new value
2215 * \param position the frame number
2216 * \param length the maximum number of frames when interpreting negative keyframe times,
2217 * <=0 if you don't care or need that
2218 * \return true if error
2221 int mlt_properties_anim_set( mlt_properties self, const char *name, const char *value, int position, int length )
2225 if ( !self || !name ) return error;
2227 // Fetch the property to work with
2228 mlt_property property = mlt_properties_fetch( self, name );
2230 // Set it if not NULL
2233 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2234 double fps = mlt_profile_fps( profile );
2235 property_list *list = self->local;
2236 error = mlt_property_anim_set_string( property, value,
2237 fps, list->locale, position, length );
2238 mlt_properties_do_mirror( self, name );
2241 mlt_events_fire( self, "property-changed", name, NULL );
2246 /** Get an integer associated to the name at a frame position.
2248 * \public \memberof mlt_properties_s
2249 * \param self a properties list
2250 * \param name the property to get
2251 * \param position the frame number
2252 * \param length the maximum number of frames when interpreting negative keyframe times,
2253 * <=0 if you don't care or need that
2254 * \return the integer value, 0 if not found (which may also be a legitimate value)
2257 int mlt_properties_anim_get_int( mlt_properties self, const char *name, int position, int length )
2259 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2260 double fps = mlt_profile_fps( profile );
2261 property_list *list = self->local;
2262 mlt_property value = mlt_properties_find( self, name );
2263 return value == NULL ? 0 : mlt_property_anim_get_int( value, fps, list->locale, position, length );
2266 /** Set a property to an integer value at a frame position.
2268 * \public \memberof mlt_properties_s
2269 * \param self a properties list
2270 * \param name the property to set
2271 * \param value the integer
2272 * \param position the frame number
2273 * \param length the maximum number of frames when interpreting negative keyframe times,
2274 * <=0 if you don't care or need that
2275 * \param keyframe_type the interpolation method for this keyframe
2276 * \return true if error
2279 int mlt_properties_anim_set_int( mlt_properties self, const char *name, int value,
2280 int position, int length, mlt_keyframe_type keyframe_type )
2284 if ( !self || !name ) return error;
2286 // Fetch the property to work with
2287 mlt_property property = mlt_properties_fetch( self, name );
2289 // Set it if not NULL
2290 if ( property != NULL )
2292 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2293 double fps = mlt_profile_fps( profile );
2294 property_list *list = self->local;
2295 error = mlt_property_anim_set_int( property, value, fps, list->locale, position, length, keyframe_type );
2296 mlt_properties_do_mirror( self, name );
2299 mlt_events_fire( self, "property-changed", name, NULL );
2304 /** Get a real number associated to the name at a frame position.
2306 * \public \memberof mlt_properties_s
2307 * \param self a properties list
2308 * \param name the property to get
2309 * \param position the frame number
2310 * \param length the maximum number of frames when interpreting negative keyframe times,
2311 * <=0 if you don't care or need that
2312 * \return the real number, 0 if not found (which may also be a legitimate value)
2315 double mlt_properties_anim_get_double( mlt_properties self, const char *name, int position, int length )
2317 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2318 double fps = mlt_profile_fps( profile );
2319 property_list *list = self->local;
2320 mlt_property value = mlt_properties_find( self, name );
2321 return value == NULL ? 0.0 : mlt_property_anim_get_double( value, fps, list->locale, position, length );
2324 /** Set a property to a real number at a frame position.
2326 * \public \memberof mlt_properties_s
2327 * \param self a properties list
2328 * \param name the property to set
2329 * \param value the real number
2330 * \param position the frame number
2331 * \param length the maximum number of frames when interpreting negative keyframe times,
2332 * <=0 if you don't care or need that
2333 * \param keyframe_type the interpolation method for this keyframe
2334 * \return true if error
2337 int mlt_properties_anim_set_double( mlt_properties self, const char *name, double value,
2338 int position, int length, mlt_keyframe_type keyframe_type )
2342 if ( !self || !name ) return error;
2344 // Fetch the property to work with
2345 mlt_property property = mlt_properties_fetch( self, name );
2347 // Set it if not NULL
2348 if ( property != NULL )
2350 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2351 double fps = mlt_profile_fps( profile );
2352 property_list *list = self->local;
2353 error = mlt_property_anim_set_double( property, value, fps, list->locale, position, length, keyframe_type );
2354 mlt_properties_do_mirror( self, name );
2357 mlt_events_fire( self, "property-changed", name, NULL );
2362 /** Get the animation associated to the name.
2364 * \public \memberof mlt_properties_s
2365 * \param self a properties list
2366 * \param name the property to get
2367 * \return The animation object or NULL if the property has no animation
2370 mlt_animation mlt_properties_get_animation( mlt_properties self, const char *name )
2372 mlt_property value = mlt_properties_find( self, name );
2373 return value == NULL ? NULL : mlt_property_get_animation( value );
2376 /** Set a property to a rectangle value.
2378 * \public \memberof mlt_properties_s
2379 * \param self a properties list
2380 * \param name the property to set
2381 * \param value the rectangle
2382 * \return true if error
2385 extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value )
2389 if ( !self || !name ) return error;
2391 // Fetch the property to work with
2392 mlt_property property = mlt_properties_fetch( self, name );
2394 // Set it if not NULL
2395 if ( property != NULL )
2397 error = mlt_property_set_rect( property, value );
2398 mlt_properties_do_mirror( self, name );
2401 mlt_events_fire( self, "property-changed", name, NULL );
2406 /** Get a rectangle associated to the name.
2408 * \public \memberof mlt_properties_s
2409 * \param self a properties list
2410 * \param name the property to get
2411 * \return the rectangle value, the rectangle fields will be DBL_MIN if not found
2414 extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char* name )
2416 property_list *list = self->local;
2417 mlt_property value = mlt_properties_find( self, name );
2418 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
2419 return value == NULL ? rect : mlt_property_get_rect( value, list->locale );
2422 /** Set a property to a rectangle value at a frame position.
2424 * \public \memberof mlt_properties_s
2425 * \param self a properties list
2426 * \param name the property to set
2427 * \param value the rectangle
2428 * \param position the frame number
2429 * \param length the maximum number of frames when interpreting negative keyframe times,
2430 * <=0 if you don't care or need that
2431 * \param keyframe_type the interpolation method for this keyframe
2432 * \return true if error
2435 extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_rect value,
2436 int position, int length , mlt_keyframe_type keyframe_type )
2440 if ( !self || !name ) return error;
2442 // Fetch the property to work with
2443 mlt_property property = mlt_properties_fetch( self, name );
2445 // Set it if not NULL
2446 if ( property != NULL )
2448 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2449 double fps = mlt_profile_fps( profile );
2450 property_list *list = self->local;
2451 error = mlt_property_anim_set_rect( property, value, fps, list->locale, position, length, keyframe_type );
2452 mlt_properties_do_mirror( self, name );
2455 mlt_events_fire( self, "property-changed", name, NULL );
2460 /** Get a rectangle associated to the name at a frame position.
2462 * \public \memberof mlt_properties_s
2463 * \param self a properties list
2464 * \param name the property to get
2465 * \param position the frame number
2466 * \param length the maximum number of frames when interpreting negative keyframe times,
2467 * <=0 if you don't care or need that
2468 * \return the rectangle value, the rectangle fields will be DBL_MIN if not found
2471 extern mlt_rect mlt_properties_anim_get_rect( mlt_properties self, const char *name, int position, int length )
2473 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2474 double fps = mlt_profile_fps( profile );
2475 property_list *list = self->local;
2476 mlt_property value = mlt_properties_find( self, name );
2477 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
2478 return value == NULL ? rect : mlt_property_anim_get_rect( value, fps, list->locale, position, length );