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 !strcmp( list->name[ i ], name ) )
511 value = list->value[ i ];
514 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
515 if ( !strcmp( list->name[ i ], name ) )
516 value = list->value[ i ];
518 mlt_properties_unlock( self );
523 /** Add a new property.
525 * \private \memberof mlt_properties_s
526 * \param self a properties list
527 * \param name the name of the new property
528 * \return the new property
531 static mlt_property mlt_properties_add( mlt_properties self, const char *name )
533 property_list *list = self->local;
534 int key = generate_hash( name );
537 mlt_properties_lock( self );
539 // Check that we have space and resize if necessary
540 if ( list->count == list->size )
543 list->name = realloc( list->name, list->size * sizeof( const char * ) );
544 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
547 // Assign name/value pair
548 list->name[ list->count ] = strdup( name );
549 list->value[ list->count ] = mlt_property_init( );
551 // Assign to hash table
552 if ( list->hash[ key ] == 0 )
553 list->hash[ key ] = list->count + 1;
555 // Return and increment count accordingly
556 result = list->value[ list->count ++ ];
558 mlt_properties_unlock( self );
563 /** Fetch a property by name and add one if not found.
565 * \private \memberof mlt_properties_s
566 * \param self a properties list
567 * \param name the property to lookup or add
568 * \return the property
571 static mlt_property mlt_properties_fetch( mlt_properties self, const char *name )
573 // Try to find an existing property first
574 mlt_property property = mlt_properties_find( self, name );
576 // If it wasn't found, create one
577 if ( property == NULL )
578 property = mlt_properties_add( self, name );
580 // Return the property
584 /** Copy a property to another properties list.
586 * \public \memberof mlt_properties_s
587 * \author Zach <zachary.drew@gmail.com>
588 * \param self the properties to copy to
589 * \param that the properties to copy from
590 * \param name the name of the property to copy
593 void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name )
595 // Make sure the source property isn't null.
596 mlt_property that_prop = mlt_properties_find( that, name );
597 if( that_prop == NULL )
600 mlt_property_pass( mlt_properties_fetch( self, name ), that_prop );
603 /** Copy all properties specified in a comma-separated list to another properties list.
605 * White space is also a delimiter.
606 * \public \memberof mlt_properties_s
607 * \author Zach <zachary.drew@gmail.com>
608 * \param self the properties to copy to
609 * \param that the properties to copy from
610 * \param list a delimited list of property names
611 * \return true if error
615 int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list )
617 if ( !self || !that || !list ) return 1;
618 char *props = strdup( list );
620 const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines
625 count = strcspn( ptr, delim );
627 if( ptr[count] == '\0' )
630 ptr[count] = '\0'; // Make it a real string
632 mlt_properties_pass_property( self, that, ptr );
636 ptr += strspn( ptr, delim );
645 /** Set a property to a string.
647 * The property name "properties" is reserved to load the preset in \p value.
648 * When the value begins with '@' then it is interpreted as a very simple math
649 * expression containing only the +, -, *, and / operators.
650 * The event "property-changed" is fired after the property has been set.
652 * This makes a copy of the string value you supply.
653 * \public \memberof mlt_properties_s
654 * \param self a properties list
655 * \param name the property to set
656 * \param value the property's new value
657 * \return true if error
660 int mlt_properties_set( mlt_properties self, const char *name, const char *value )
664 if ( !self || !name ) return error;
666 // Fetch the property to work with
667 mlt_property property = mlt_properties_fetch( self, name );
669 // Set it if not NULL
670 if ( property == NULL )
672 mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name );
674 else if ( value == NULL )
676 error = mlt_property_set_string( property, value );
677 mlt_properties_do_mirror( self, name );
679 else if ( *value != '@' )
681 error = mlt_property_set_string( property, value );
682 mlt_properties_do_mirror( self, name );
683 if ( !strcmp( name, "properties" ) )
684 mlt_properties_preset( self, value );
686 else if ( value[ 0 ] == '@' )
695 while ( *value != '\0' )
697 int length = strcspn( value, "+-*/" );
699 // Get the identifier
700 strncpy( id, value, length );
704 // Determine the value
705 if ( isdigit( id[ 0 ] ) )
707 #if defined(__GLIBC__) || defined(__DARWIN__)
708 property_list *list = self->local;
710 current = strtod_l( id, NULL, list->locale );
713 current = strtod( id, NULL );
717 current = mlt_properties_get_double( self, id );
720 // Apply the operation
733 total = total / current;
738 op = *value != '\0' ? *value ++ : ' ';
741 error = mlt_property_set_double( property, total );
742 mlt_properties_do_mirror( self, name );
745 mlt_events_fire( self, "property-changed", name, NULL );
750 /** Set or default a property to a string.
752 * This makes a copy of the string value you supply.
753 * \public \memberof mlt_properties_s
754 * \param self a properties list
755 * \param name the property to set
756 * \param value the string value to set or NULL to use the default
757 * \param def the default string if value is NULL
758 * \return true if error
761 int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def )
763 return mlt_properties_set( self, name, value == NULL ? def : value );
766 /** Get a string value by name.
768 * Do not free the returned string. It's lifetime is controlled by the property
769 * and this properties object.
770 * \public \memberof mlt_properties_s
771 * \param self a properties list
772 * \param name the property to get
773 * \return the property's string value or NULL if it does not exist
776 char *mlt_properties_get( mlt_properties self, const char *name )
779 mlt_property value = mlt_properties_find( self, name );
782 property_list *list = self->local;
783 result = mlt_property_get_string_l( value, list->locale );
788 /** Get a property name by index.
790 * Do not free the returned string.
791 * \public \memberof mlt_properties_s
792 * \param self a properties list
793 * \param index the numeric index of the property
794 * \return the name of the property or NULL if index is out of range
797 char *mlt_properties_get_name( mlt_properties self, int index )
799 if ( !self ) return NULL;
800 property_list *list = self->local;
801 if ( index >= 0 && index < list->count )
802 return list->name[ index ];
806 /** Get a property's string value by index.
808 * Do not free the returned string.
809 * \public \memberof mlt_properties_s
810 * \param self a properties list
811 * \param index the numeric index of the property
812 * \return the property value as a string or NULL if the index is out of range
815 char *mlt_properties_get_value( mlt_properties self, int index )
817 if ( !self ) return NULL;
818 property_list *list = self->local;
819 if ( index >= 0 && index < list->count )
820 return mlt_property_get_string_l( list->value[ index ], list->locale );
824 /** Get a data value by index.
826 * Do not free the returned pointer if you supplied a destructor function when you
828 * \public \memberof mlt_properties_s
829 * \param self a properties list
830 * \param index the numeric index of the property
831 * \param[out] size the size of the binary data in bytes or NULL if the index is out of range
834 void *mlt_properties_get_data_at( mlt_properties self, int index, int *size )
836 if ( !self ) return NULL;
837 property_list *list = self->local;
838 if ( index >= 0 && index < list->count )
839 return mlt_property_get_data( list->value[ index ], size );
843 /** Return the number of items in the list.
845 * \public \memberof mlt_properties_s
846 * \param self a properties list
847 * \return the number of property objects or -1 if error
850 int mlt_properties_count( mlt_properties self )
852 if ( !self ) return -1;
853 property_list *list = self->local;
857 /** Set a value by parsing a name=value string.
859 * \public \memberof mlt_properties_s
860 * \param self a properties list
861 * \param namevalue a string containing name and value delimited by '='
862 * \return true if there was an error
865 int mlt_properties_parse( mlt_properties self, const char *namevalue )
867 if ( !self ) return 1;
868 char *name = strdup( namevalue );
871 char *ptr = strchr( name, '=' );
879 value = strdup( ptr );
884 value = strdup( ptr );
885 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
886 value[ strlen( value ) - 1 ] = '\0';
891 value = strdup( "" );
894 error = mlt_properties_set( self, name, value );
902 /** Get an integer associated to the name.
904 * \public \memberof mlt_properties_s
905 * \param self a properties list
906 * \param name the property to get
907 * \return The integer value, 0 if not found (which may also be a legitimate value)
910 int mlt_properties_get_int( mlt_properties self, const char *name )
913 mlt_property value = mlt_properties_find( self, name );
916 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
917 double fps = mlt_profile_fps( profile );
918 property_list *list = self->local;
919 result = mlt_property_get_int( value, fps, list->locale );
924 /** Set a property to an integer value.
926 * \public \memberof mlt_properties_s
927 * \param self a properties list
928 * \param name the property to set
929 * \param value the integer
930 * \return true if error
933 int mlt_properties_set_int( mlt_properties self, const char *name, int value )
937 if ( !self || !name ) return error;
939 // Fetch the property to work with
940 mlt_property property = mlt_properties_fetch( self, name );
942 // Set it if not NULL
943 if ( property != NULL )
945 error = mlt_property_set_int( property, value );
946 mlt_properties_do_mirror( self, name );
949 mlt_events_fire( self, "property-changed", name, NULL );
954 /** Get a 64-bit integer associated to the name.
956 * \public \memberof mlt_properties_s
957 * \param self a properties list
958 * \param name the property to get
959 * \return the integer value, 0 if not found (which may also be a legitimate value)
962 int64_t mlt_properties_get_int64( mlt_properties self, const char *name )
964 mlt_property value = mlt_properties_find( self, name );
965 return value == NULL ? 0 : mlt_property_get_int64( value );
968 /** Set a property to a 64-bit integer value.
970 * \public \memberof mlt_properties_s
971 * \param self a properties list
972 * \param name the property to set
973 * \param value the integer
974 * \return true if error
977 int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value )
981 if ( !self || !name ) return error;
983 // Fetch the property to work with
984 mlt_property property = mlt_properties_fetch( self, name );
986 // Set it if not NULL
987 if ( property != NULL )
989 error = mlt_property_set_int64( property, value );
990 mlt_properties_do_mirror( self, name );
993 mlt_events_fire( self, "property-changed", name, NULL );
998 /** Get a floating point value associated to the name.
1000 * \public \memberof mlt_properties_s
1001 * \param self a properties list
1002 * \param name the property to get
1003 * \return the floating point, 0 if not found (which may also be a legitimate value)
1006 double mlt_properties_get_double( mlt_properties self, const char *name )
1009 mlt_property value = mlt_properties_find( self, name );
1012 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1013 double fps = mlt_profile_fps( profile );
1014 property_list *list = self->local;
1015 result = mlt_property_get_double( value, fps, list->locale );
1020 /** Set a property to a floating point value.
1022 * \public \memberof mlt_properties_s
1023 * \param self a properties list
1024 * \param name the property to set
1025 * \param value the floating point value
1026 * \return true if error
1029 int mlt_properties_set_double( mlt_properties self, const char *name, double value )
1033 if ( !self || !name ) return error;
1035 // Fetch the property to work with
1036 mlt_property property = mlt_properties_fetch( self, name );
1038 // Set it if not NULL
1039 if ( property != NULL )
1041 error = mlt_property_set_double( property, value );
1042 mlt_properties_do_mirror( self, name );
1045 mlt_events_fire( self, "property-changed", name, NULL );
1050 /** Get a position value associated to the name.
1052 * \public \memberof mlt_properties_s
1053 * \param self a properties list
1054 * \param name the property to get
1055 * \return the position, 0 if not found (which may also be a legitimate value)
1058 mlt_position mlt_properties_get_position( mlt_properties self, const char *name )
1060 mlt_position result = 0;
1061 mlt_property value = mlt_properties_find( self, name );
1064 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1065 double fps = mlt_profile_fps( profile );
1066 property_list *list = self->local;
1067 result = mlt_property_get_position( value, fps, list->locale );
1072 /** Set a property to a position value.
1074 * \public \memberof mlt_properties_s
1075 * \param self a properties list
1076 * \param name the property to get
1077 * \param value the position
1078 * \return true if error
1081 int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value )
1085 if ( !self || !name ) return error;
1087 // Fetch the property to work with
1088 mlt_property property = mlt_properties_fetch( self, name );
1090 // Set it if not NULL
1091 if ( property != NULL )
1093 error = mlt_property_set_position( property, value );
1094 mlt_properties_do_mirror( self, name );
1097 mlt_events_fire( self, "property-changed", name, NULL );
1102 /** Get a binary data value associated to the name.
1104 * Do not free the returned pointer if you supplied a destructor function
1105 * when you set this property.
1106 * \public \memberof mlt_properties_s
1107 * \param self a properties list
1108 * \param name the property to get
1109 * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know)
1112 void *mlt_properties_get_data( mlt_properties self, const char *name, int *length )
1114 mlt_property value = mlt_properties_find( self, name );
1115 return value == NULL ? NULL : mlt_property_get_data( value, length );
1118 /** Store binary data as a property.
1120 * \public \memberof mlt_properties_s
1121 * \param self a properties list
1122 * \param name the property to set
1123 * \param value an opaque pointer to binary data
1124 * \param length the size of the binary data in bytes (optional)
1125 * \param destroy a function to deallocate the binary data when the property is closed (optional)
1126 * \param serialise a function that can serialize the binary data as text (optional)
1127 * \return true if error
1130 int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
1134 if ( !self || !name ) return error;
1136 // Fetch the property to work with
1137 mlt_property property = mlt_properties_fetch( self, name );
1139 // Set it if not NULL
1140 if ( property != NULL )
1141 error = mlt_property_set_data( property, value, length, destroy, serialise );
1143 mlt_events_fire( self, "property-changed", name, NULL );
1148 /** Rename a property.
1150 * \public \memberof mlt_properties_s
1151 * \param self a properties list
1152 * \param source the property to rename
1153 * \param dest the new name
1154 * \return true if the name is already in use
1157 int mlt_properties_rename( mlt_properties self, const char *source, const char *dest )
1159 mlt_property value = mlt_properties_find( self, dest );
1161 if ( value == NULL )
1163 property_list *list = self->local;
1167 mlt_properties_lock( self );
1168 for ( i = 0; i < list->count; i ++ )
1170 if ( !strcmp( list->name[ i ], source ) )
1172 free( list->name[ i ] );
1173 list->name[ i ] = strdup( dest );
1174 list->hash[ generate_hash( dest ) ] = i + 1;
1178 mlt_properties_unlock( self );
1181 return value != NULL;
1184 /** Dump the properties to a file handle.
1186 * \public \memberof mlt_properties_s
1187 * \param self a properties list
1188 * \param output a file handle
1191 void mlt_properties_dump( mlt_properties self, FILE *output )
1193 if ( !self || !output ) return;
1194 property_list *list = self->local;
1196 for ( i = 0; i < list->count; i ++ )
1197 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1198 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1201 /** Output the properties to a file handle.
1203 * This version includes reference counts and does not put each property on a new line.
1204 * \public \memberof mlt_properties_s
1205 * \param self a properties pointer
1206 * \param title a string to preface the output
1207 * \param output a file handle
1209 void mlt_properties_debug( mlt_properties self, const char *title, FILE *output )
1211 if ( !self || !output ) return;
1212 if ( output == NULL ) output = stderr;
1213 fprintf( output, "%s: ", title );
1216 property_list *list = self->local;
1218 fprintf( output, "[ ref=%d", list->ref_count );
1219 for ( i = 0; i < list->count; i ++ )
1220 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1221 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1223 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) );
1224 fprintf( output, " ]" );
1226 fprintf( output, "\n" );
1229 /** Save the properties to a file by name.
1231 * This uses the dump format - one line per property.
1232 * \public \memberof mlt_properties_s
1233 * \param self a properties list
1234 * \param filename the name of a file to create or overwrite
1235 * \return true if there was an error
1238 int mlt_properties_save( mlt_properties self, const char *filename )
1241 if ( !self || !filename ) return error;
1242 FILE *f = fopen( filename, "w" );
1245 mlt_properties_dump( self, f );
1252 /* This is a very basic cross platform fnmatch replacement - it will fail in
1253 * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
1256 /** Test whether a filename or pathname matches a shell-style pattern.
1258 * \private \memberof mlt_properties_s
1259 * \param wild a string containing a wildcard pattern
1260 * \param file the name of a file to test against
1261 * \return true if the file name matches the wildcard pattern
1264 static int mlt_fnmatch( const char *wild, const char *file )
1269 while( f < strlen( file ) && w < strlen( wild ) )
1271 if ( wild[ w ] == '*' )
1274 if ( w == strlen( wild ) )
1276 while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
1279 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
1284 else if ( wild[ 0 ] == '*' )
1294 return strlen( file ) == f && strlen( wild ) == w;
1297 /** Compare the string or serialized value of two properties.
1299 * \private \memberof mlt_properties_s
1300 * \param self a property
1301 * \param that a property
1302 * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that
1305 static int mlt_compare( const void *self, const void *that )
1307 return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) );
1310 /** Get the contents of a directory.
1312 * Obtains an optionally sorted list of the files found in a directory with a specific wild card.
1313 * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
1314 * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
1315 * \public \memberof mlt_properties_s
1316 * \param self a properties list
1317 * \param dirname the name of the directory
1318 * \param pattern a wildcard pattern to filter the directory listing
1319 * \param sort Do you want to sort the directory listing?
1320 * \return the number of items in the directory listing
1323 int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort )
1325 DIR *dir = opendir( dirname );
1330 struct dirent *de = readdir( dir );
1331 char fullname[ 1024 ];
1334 sprintf( key, "%d", mlt_properties_count( self ) );
1335 snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
1336 if ( pattern == NULL )
1337 mlt_properties_set( self, key, fullname );
1338 else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
1339 mlt_properties_set( self, key, fullname );
1340 de = readdir( dir );
1346 if ( sort && mlt_properties_count( self ) )
1348 property_list *list = self->local;
1349 mlt_properties_lock( self );
1350 qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare );
1351 mlt_properties_unlock( self );
1354 return mlt_properties_count( self );
1357 /** Close a properties object.
1359 * Deallocates the properties object and everything it contains.
1360 * \public \memberof mlt_properties_s
1361 * \param self a properties object
1364 void mlt_properties_close( mlt_properties self )
1366 if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 )
1368 if ( self->close != NULL )
1370 self->close( self->close_object );
1374 property_list *list = self->local;
1377 #if _MLT_PROPERTY_CHECKS_ == 1
1379 mlt_properties_debug( self, "Closing", stderr );
1382 #ifdef _MLT_PROPERTY_CHECKS_
1383 // Increment destroyed count
1384 properties_destroyed ++;
1386 // Show current stats - these should match when the app is closed
1387 mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
1390 // Clean up names and values
1391 for ( index = list->count - 1; index >= 0; index -- )
1393 mlt_property_close( list->value[ index ] );
1394 free( list->name[ index ] );
1397 #if defined(__linux__) || defined(__DARWIN__)
1400 freelocale( list->locale );
1403 // Clear up the list
1404 pthread_mutex_destroy( &list->mutex );
1406 free( list->value );
1409 // Free self now if self has no child
1410 if ( self->child == NULL )
1416 /** Determine if the properties list is really just a sequence or ordered list.
1418 * \public \memberof mlt_properties_s
1419 * \param properties a properties list
1420 * \return true if all of the property names are numeric (a sequence)
1423 int mlt_properties_is_sequence( mlt_properties properties )
1426 int n = mlt_properties_count( properties );
1427 for ( i = 0; i < n; i++ )
1428 if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) )
1433 /** \brief YAML Tiny Parser context structure
1435 * YAML is a nifty text format popular in the Ruby world as a cleaner,
1436 * less verbose alternative to XML. See this Wikipedia topic for an overview:
1437 * http://en.wikipedia.org/wiki/YAML
1438 * The YAML specification is at:
1440 * YAML::Tiny is a Perl module that specifies a subset of YAML that we are
1441 * using here (for the same reasons):
1442 * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm
1446 struct yaml_parser_context
1451 mlt_deque index_stack;
1454 unsigned int block_indent;
1457 typedef struct yaml_parser_context *yaml_parser;
1459 /** Remove spaces from the left side of a string.
1461 * \param s the string to trim
1462 * \return the number of characters removed
1465 static unsigned int ltrim( char **s )
1469 int n = strlen( c );
1470 for ( i = 0; i < n && *c == ' '; i++, c++ );
1475 /** Remove spaces from the right side of a string.
1477 * \param s the string to trim
1478 * \return the number of characters removed
1481 static unsigned int rtrim( char *s )
1483 int n = strlen( s );
1485 for ( i = n; i > 0 && s[i - 1] == ' '; --i )
1490 /** Parse a line of YAML Tiny.
1492 * Adds a property if needed.
1493 * \private \memberof yaml_parser_context
1494 * \param context a YAML Tiny Parser context
1495 * \param namevalue a line of YAML Tiny
1496 * \return true if there was an error
1499 static int parse_yaml( yaml_parser context, const char *namevalue )
1501 char *name_ = strdup( namevalue );
1505 char *ptr = strchr( name, ':' );
1506 unsigned int indent = ltrim( &name );
1507 mlt_properties properties = mlt_deque_peek_back( context->stack );
1509 // Ascending one more levels in the tree
1510 if ( indent < context->level )
1513 unsigned int n = ( context->level - indent ) / 2;
1514 for ( i = 0; i < n; i++ )
1516 mlt_deque_pop_back( context->stack );
1517 context->index = mlt_deque_pop_back_int( context->index_stack );
1519 properties = mlt_deque_peek_back( context->stack );
1520 context->level = indent;
1523 // Descending a level in the tree
1524 else if ( indent > context->level && context->block == 0 )
1526 context->level = indent;
1529 // If there is a colon that is not part of a block
1530 if ( ptr && ( indent == context->level ) )
1532 // Reset block processing
1533 if ( context->block_name )
1535 free( context->block_name );
1536 context->block_name = NULL;
1540 // Terminate the name and setup the value pointer
1544 char *comment = strchr( ptr, '#' );
1550 // Trim leading and trailing spaces from bare value
1554 // No value means a child
1555 if ( strcmp( ptr, "" ) == 0 )
1557 mlt_properties child = mlt_properties_new();
1558 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1559 mlt_properties_set_data( properties, name, child, 0,
1560 ( mlt_destructor )mlt_properties_close, NULL );
1561 mlt_deque_push_back( context->stack, child );
1562 mlt_deque_push_back_int( context->index_stack, context->index );
1568 // A dash indicates a sequence item
1569 if ( name[0] == '-' )
1571 mlt_properties child = mlt_properties_new();
1574 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1575 snprintf( key, sizeof(key), "%d", context->index++ );
1576 mlt_properties_set_data( properties, key, child, 0,
1577 ( mlt_destructor )mlt_properties_close, NULL );
1578 mlt_deque_push_back( context->stack, child );
1579 mlt_deque_push_back_int( context->index_stack, context->index );
1582 context->level += ltrim( &name ) + 1;
1590 value = strdup( ptr );
1591 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1592 value[ strlen( value ) - 1 ] = 0;
1595 // Value is folded or unfolded block
1596 else if ( *ptr == '|' || *ptr == '>' )
1598 context->block = *ptr;
1599 context->block_name = strdup( name );
1600 context->block_indent = 0;
1601 value = strdup( "" );
1607 value = strdup( ptr );
1611 // A list of scalars
1612 else if ( name[0] == '-' )
1614 // Reset block processing
1615 if ( context->block_name )
1617 free( context->block_name );
1618 context->block_name = NULL;
1624 snprintf( key, sizeof(key), "%d", context->index++ );
1628 char *comment = strchr( ptr, '#' );
1632 // Trim leading and trailing spaces from bare value
1640 value = strdup( ptr );
1641 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1642 value[ strlen( value ) - 1 ] = 0;
1645 // Value is folded or unfolded block
1646 else if ( *ptr == '|' || *ptr == '>' )
1648 context->block = *ptr;
1649 context->block_name = strdup( key );
1650 context->block_indent = 0;
1651 value = strdup( "" );
1657 value = strdup( ptr );
1661 name = name_ = strdup( key );
1665 else if ( context->block == '|' )
1667 if ( context->block_indent == 0 )
1668 context->block_indent = indent;
1669 if ( indent > context->block_indent )
1670 name = &name_[ context->block_indent ];
1672 char *old_value = mlt_properties_get( properties, context->block_name );
1673 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1674 strcpy( value, old_value );
1675 if ( strcmp( old_value, "" ) )
1676 strcat( value, "\n" );
1677 strcat( value, name );
1678 name = context->block_name;
1682 else if ( context->block == '>' )
1686 char *old_value = mlt_properties_get( properties, context->block_name );
1688 // Blank line (prepended with spaces) is new line
1689 if ( strcmp( name, "" ) == 0 )
1691 value = calloc( 1, strlen( old_value ) + 2 );
1692 strcat( value, old_value );
1693 strcat( value, "\n" );
1695 // Concatenate with space
1698 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1699 strcat( value, old_value );
1700 if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' )
1701 strcat( value, " " );
1702 strcat( value, name );
1704 name = context->block_name;
1709 value = strdup( "" );
1712 error = mlt_properties_set( properties, name, value );
1714 if ( !strcmp( name, "LC_NUMERIC" ) )
1715 mlt_properties_set_lcnumeric( properties, value );
1723 /** Parse a YAML Tiny file by name.
1725 * \public \memberof mlt_properties_s
1726 * \param filename the name of a text file containing YAML Tiny
1727 * \return a new properties list
1730 mlt_properties mlt_properties_parse_yaml( const char *filename )
1732 // Construct a standalone properties object
1733 mlt_properties self = mlt_properties_new( );
1738 FILE *file = fopen( filename, "r" );
1740 // Load contents of file
1745 char *ptemp = &temp[ 0 ];
1747 // Default to LC_NUMERIC = C
1748 mlt_properties_set_lcnumeric( self, "C" );
1751 yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) );
1752 context->stack = mlt_deque_init();
1753 context->index_stack = mlt_deque_init();
1754 mlt_deque_push_back( context->stack, self );
1755 mlt_deque_push_back_int( context->index_stack, 0 );
1757 // Read each string from the file
1758 while( fgets( temp, 1024, file ) )
1760 // Check for end-of-stream
1761 if ( strncmp( ptemp, "...", 3 ) == 0 )
1765 temp[ strlen( temp ) - 1 ] = '\0';
1767 // Skip blank lines, comment lines, and document separator
1768 if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 )
1769 && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) )
1770 parse_yaml( context, temp );
1775 mlt_deque_close( context->stack );
1776 mlt_deque_close( context->index_stack );
1777 if ( context->block_name )
1778 free( context->block_name );
1783 // Return the pointer
1788 * YAML Tiny Serializer
1791 /** How many bytes to grow at a time */
1792 #define STRBUF_GROWTH (1024)
1794 /** \brief Private to mlt_properties_s, a self-growing buffer for building strings
1804 typedef struct strbuf_s *strbuf;
1806 /** Create a new string buffer
1808 * \private \memberof strbuf_s
1809 * \return a new string buffer
1812 static strbuf strbuf_new( )
1814 strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) );
1815 buffer->size = STRBUF_GROWTH;
1816 buffer->string = calloc( 1, buffer->size );
1820 /** Destroy a string buffer
1822 * \private \memberof strbuf_s
1823 * \param buffer the string buffer to close
1826 static void strbuf_close( strbuf buffer )
1828 // We do not free buffer->string; strbuf user must save that pointer
1834 /** Format a string into a string buffer
1836 * A variable number of arguments follows the format string - one for each
1838 * \private \memberof strbuf_s
1839 * \param buffer the string buffer to write into
1840 * \param format a string that contains text and formatting instructions
1841 * \return the formatted string
1844 static char *strbuf_printf( strbuf buffer, const char *format, ... )
1846 while ( buffer->string )
1849 va_start( ap, format );
1850 size_t len = strlen( buffer->string );
1851 size_t remain = buffer->size - len - 1;
1852 int need = vsnprintf( buffer->string + len, remain, format, ap );
1854 if ( need > -1 && need < remain )
1856 buffer->string[ len ] = 0;
1857 buffer->size += need + STRBUF_GROWTH;
1858 buffer->string = realloc( buffer->string, buffer->size );
1860 return buffer->string;
1863 /** Indent a line of YAML Tiny.
1865 * \private \memberof strbuf_s
1866 * \param output a string buffer
1867 * \param indent the number of spaces to indent
1870 static inline void indent_yaml( strbuf output, int indent )
1873 for ( j = 0; j < indent; j++ )
1874 strbuf_printf( output, " " );
1877 static void strbuf_escape( strbuf output, const char *value, char c )
1879 char *v = strdup( value );
1881 char *found = strchr( s, c );
1886 strbuf_printf( output, "%s\\%c", s, c );
1888 found = strchr( s, c );
1890 strbuf_printf( output, "%s", s );
1894 /** Convert a line string into a YAML block literal.
1896 * \private \memberof strbuf_s
1897 * \param output a string buffer
1898 * \param value the string to format as a block literal
1899 * \param indent the number of spaces to indent
1902 static void output_yaml_block_literal( strbuf output, const char *value, int indent )
1904 char *v = strdup( value );
1906 char *eol = strchr( sol, '\n' );
1910 indent_yaml( output, indent );
1912 strbuf_printf( output, "%s\n", sol );
1914 eol = strchr( sol, '\n' );
1916 indent_yaml( output, indent );
1917 strbuf_printf( output, "%s\n", sol );
1921 /** Recursively serialize a properties list into a string buffer as YAML Tiny.
1923 * \private \memberof mlt_properties_s
1924 * \param self a properties list
1925 * \param output a string buffer to hold the serialized YAML Tiny
1926 * \param indent the number of spaces to indent (for recursion, initialize to 0)
1927 * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)?
1930 static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence )
1932 property_list *list = self->local;
1935 for ( i = 0; i < list->count; i ++ )
1937 // This implementation assumes that all data elements are property lists.
1938 // Unfortunately, we do not have run time type identification.
1939 mlt_properties child = mlt_property_get_data( list->value[ i ], NULL );
1941 if ( mlt_properties_is_sequence( self ) )
1943 // Ignore hidden/non-serialisable items
1944 if ( list->name[ i ][ 0 ] != '_' )
1946 // Indicate a sequence item
1947 indent_yaml( output, indent );
1948 strbuf_printf( output, "- " );
1950 // If the value can be represented as a string
1951 const char *value = mlt_properties_get( self, list->name[ i ] );
1952 if ( value && strcmp( value, "" ) )
1954 // Determine if this is an unfolded block literal
1955 if ( strchr( value, '\n' ) )
1957 strbuf_printf( output, "|\n" );
1958 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) );
1960 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1962 strbuf_printf( output, "\"" );
1963 strbuf_escape( output, value, '"' );
1964 strbuf_printf( output, "\"\n", value );
1968 strbuf_printf( output, "%s\n", value );
1974 serialise_yaml( child, output, indent + 2, 1 );
1978 // Assume this is a normal map-oriented properties list
1979 const char *value = mlt_properties_get( self, list->name[ i ] );
1981 // Ignore hidden/non-serialisable items
1982 // If the value can be represented as a string
1983 if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) )
1985 if ( is_parent_sequence == 0 )
1986 indent_yaml( output, indent );
1988 is_parent_sequence = 0;
1990 // Determine if this is an unfolded block literal
1991 if ( strchr( value, '\n' ) )
1993 strbuf_printf( output, "%s: |\n", list->name[ i ] );
1994 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) );
1996 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1998 strbuf_printf( output, "%s: \"", list->name[ i ] );
1999 strbuf_escape( output, value, '"' );
2000 strbuf_printf( output, "\"\n" );
2004 strbuf_printf( output, "%s: %s\n", list->name[ i ], value );
2008 // Output a child as a map item
2011 indent_yaml( output, indent );
2012 strbuf_printf( output, "%s:\n", list->name[ i ] );
2015 serialise_yaml( child, output, indent + 2, 0 );
2021 /** Serialize a properties list as a string of YAML Tiny.
2023 * The caller MUST free the returned string!
2024 * This operates on properties containing properties as a hierarchical data
2026 * \public \memberof mlt_properties_s
2027 * \param self a properties list
2028 * \return a string containing YAML Tiny that represents the properties list
2031 char *mlt_properties_serialise_yaml( mlt_properties self )
2033 if ( !self ) return NULL;
2034 const char *lc_numeric = mlt_properties_get_lcnumeric( self );
2035 strbuf b = strbuf_new();
2036 strbuf_printf( b, "---\n" );
2037 mlt_properties_set_lcnumeric( self, "C" );
2038 serialise_yaml( self, b, 0, 0 );
2039 mlt_properties_set_lcnumeric( self, lc_numeric );
2040 strbuf_printf( b, "...\n" );
2041 char *ret = b->string;
2046 /** Protect a properties list against concurrent access.
2048 * \public \memberof mlt_properties_s
2049 * \param self a properties list
2052 void mlt_properties_lock( mlt_properties self )
2055 pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex );
2058 /** End protecting a properties list against concurrent access.
2060 * \public \memberof mlt_properties_s
2061 * \param self a properties list
2064 void mlt_properties_unlock( mlt_properties self )
2067 pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex );
2070 /** Get a time string associated to the name.
2072 * Do not free the returned string. It's lifetime is controlled by the property.
2073 * \public \memberof mlt_properties_s
2074 * \param self a properties list
2075 * \param name the property to get
2076 * \param format the time format that you want
2077 * \return the property's time value or NULL if \p name does not exist or there is no profile
2080 char *mlt_properties_get_time( mlt_properties self, const char* name, mlt_time_format format )
2082 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2085 double fps = mlt_profile_fps( profile );
2086 mlt_property value = mlt_properties_find( self, name );
2087 property_list *list = self->local;
2088 return value == NULL ? NULL : mlt_property_get_time( value, format, fps, list->locale );
2093 /** Convert a frame count to a time string.
2095 * Do not free the returned string. It's lifetime is controlled by the property.
2096 * \public \memberof mlt_properties_s
2097 * \param self a properties list
2098 * \param frames the frame count to convert
2099 * \param format the time format that you want
2100 * \return the time string or NULL if error, e.g. there is no profile
2103 char *mlt_properties_frames_to_time( mlt_properties self, mlt_position frames, mlt_time_format format )
2105 const char *name = "_mlt_properties_time";
2106 mlt_properties_set_position( self, name, frames );
2107 return mlt_properties_get_time( self, name, format );
2110 /** Convert a time string to a frame count.
2112 * \public \memberof mlt_properties_s
2113 * \param self a properties list
2114 * \param time the time string to convert
2115 * \return a frame count or a negative value if error, e.g. there is no profile
2118 mlt_position mlt_properties_time_to_frames( mlt_properties self, const char *time )
2120 const char *name = "_mlt_properties_time";
2121 mlt_properties_set( self, name, time );
2122 return mlt_properties_get_position( self, name );
2125 /** Convert a numeric property to a tuple of color components.
2127 * If the property's string is red, green, blue, white, or black, then it
2128 * is converted to the corresponding opaque color tuple. Otherwise, the property
2129 * is fetched as an integer and then converted.
2130 * \public \memberof mlt_properties_s
2131 * \param self a properties list
2132 * \param name the property to get
2133 * \return a color structure
2136 mlt_color mlt_properties_get_color( mlt_properties self, const char* name )
2138 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2139 double fps = mlt_profile_fps( profile );
2140 property_list *list = self->local;
2141 mlt_property value = mlt_properties_find( self, name );
2142 mlt_color result = { 0xff, 0xff, 0xff, 0xff };
2145 const char *color = mlt_property_get_string_l( value, list->locale );
2146 unsigned int color_int = mlt_property_get_int( value, fps, list->locale );
2148 if ( !strcmp( color, "red" ) )
2154 else if ( !strcmp( color, "green" ) )
2160 else if ( !strcmp( color, "blue" ) )
2166 else if ( !strcmp( color, "black" ) )
2172 else if ( strcmp( color, "white" ) )
2174 result.r = ( color_int >> 24 ) & 0xff;
2175 result.g = ( color_int >> 16 ) & 0xff;
2176 result.b = ( color_int >> 8 ) & 0xff;
2177 result.a = ( color_int ) & 0xff;
2183 /** Set a property to an integer value by color.
2185 * \public \memberof mlt_properties_s
2186 * \param self a properties list
2187 * \param name the property to set
2188 * \param color the color
2189 * \return true if error
2192 int mlt_properties_set_color( mlt_properties self, const char *name, mlt_color color )
2196 if ( !self || !name ) return error;
2198 // Fetch the property to work with
2199 mlt_property property = mlt_properties_fetch( self, name );
2201 // Set it if not NULL
2202 if ( property != NULL )
2204 uint32_t value = ( color.r << 24 ) | ( color.g << 16 ) | ( color.b << 8 ) | color.a;
2205 error = mlt_property_set_int( property, value );
2206 mlt_properties_do_mirror( self, name );
2209 mlt_events_fire( self, "property-changed", name, NULL );
2214 /** Get a string value by name at a frame position.
2216 * Do not free the returned string. It's lifetime is controlled by the property
2217 * and this properties object.
2218 * \public \memberof mlt_properties_s
2219 * \param self a properties list
2220 * \param name the property to get
2221 * \param position the frame number
2222 * \param length the maximum number of frames when interpreting negative keyframe times,
2223 * <=0 if you don't care or need that
2224 * \return the property's string value or NULL if it does not exist
2227 char* mlt_properties_anim_get( mlt_properties self, const char *name, int position, int length )
2229 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2230 double fps = mlt_profile_fps( profile );
2231 mlt_property value = mlt_properties_find( self, name );
2232 property_list *list = self->local;
2233 return value == NULL ? NULL : mlt_property_anim_get_string( value, fps, list->locale, position, length );
2236 /** Set a property to a string at a frame position.
2238 * The event "property-changed" is fired after the property has been set.
2240 * This makes a copy of the string value you supply.
2241 * \public \memberof mlt_properties_s
2242 * \param self a properties list
2243 * \param name the property to set
2244 * \param value the property's new value
2245 * \param position the frame number
2246 * \param length the maximum number of frames when interpreting negative keyframe times,
2247 * <=0 if you don't care or need that
2248 * \return true if error
2251 int mlt_properties_anim_set( mlt_properties self, const char *name, const char *value, int position, int length )
2255 if ( !self || !name ) return error;
2257 // Fetch the property to work with
2258 mlt_property property = mlt_properties_fetch( self, name );
2260 // Set it if not NULL
2263 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2264 double fps = mlt_profile_fps( profile );
2265 property_list *list = self->local;
2266 error = mlt_property_anim_set_string( property, value,
2267 fps, list->locale, position, length );
2268 mlt_properties_do_mirror( self, name );
2271 mlt_events_fire( self, "property-changed", name, NULL );
2276 /** Get an integer associated to the name at a frame position.
2278 * \public \memberof mlt_properties_s
2279 * \param self a properties list
2280 * \param name the property to get
2281 * \param position the frame number
2282 * \param length the maximum number of frames when interpreting negative keyframe times,
2283 * <=0 if you don't care or need that
2284 * \return the integer value, 0 if not found (which may also be a legitimate value)
2287 int mlt_properties_anim_get_int( mlt_properties self, const char *name, int position, int length )
2289 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2290 double fps = mlt_profile_fps( profile );
2291 property_list *list = self->local;
2292 mlt_property value = mlt_properties_find( self, name );
2293 return value == NULL ? 0 : mlt_property_anim_get_int( value, fps, list->locale, position, length );
2296 /** Set a property to an integer value at a frame position.
2298 * \public \memberof mlt_properties_s
2299 * \param self a properties list
2300 * \param name the property to set
2301 * \param value the integer
2302 * \param position the frame number
2303 * \param length the maximum number of frames when interpreting negative keyframe times,
2304 * <=0 if you don't care or need that
2305 * \param keyframe_type the interpolation method for this keyframe
2306 * \return true if error
2309 int mlt_properties_anim_set_int( mlt_properties self, const char *name, int value,
2310 int position, int length, mlt_keyframe_type keyframe_type )
2314 if ( !self || !name ) return error;
2316 // Fetch the property to work with
2317 mlt_property property = mlt_properties_fetch( self, name );
2319 // Set it if not NULL
2320 if ( property != NULL )
2322 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2323 double fps = mlt_profile_fps( profile );
2324 property_list *list = self->local;
2325 error = mlt_property_anim_set_int( property, value, fps, list->locale, position, length, keyframe_type );
2326 mlt_properties_do_mirror( self, name );
2329 mlt_events_fire( self, "property-changed", name, NULL );
2334 /** Get a real number associated to the name at a frame position.
2336 * \public \memberof mlt_properties_s
2337 * \param self a properties list
2338 * \param name the property to get
2339 * \param position the frame number
2340 * \param length the maximum number of frames when interpreting negative keyframe times,
2341 * <=0 if you don't care or need that
2342 * \return the real number, 0 if not found (which may also be a legitimate value)
2345 double mlt_properties_anim_get_double( mlt_properties self, const char *name, int position, int length )
2347 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2348 double fps = mlt_profile_fps( profile );
2349 property_list *list = self->local;
2350 mlt_property value = mlt_properties_find( self, name );
2351 return value == NULL ? 0.0 : mlt_property_anim_get_double( value, fps, list->locale, position, length );
2354 /** Set a property to a real number at a frame position.
2356 * \public \memberof mlt_properties_s
2357 * \param self a properties list
2358 * \param name the property to set
2359 * \param value the real number
2360 * \param position the frame number
2361 * \param length the maximum number of frames when interpreting negative keyframe times,
2362 * <=0 if you don't care or need that
2363 * \param keyframe_type the interpolation method for this keyframe
2364 * \return true if error
2367 int mlt_properties_anim_set_double( mlt_properties self, const char *name, double value,
2368 int position, int length, mlt_keyframe_type keyframe_type )
2372 if ( !self || !name ) return error;
2374 // Fetch the property to work with
2375 mlt_property property = mlt_properties_fetch( self, name );
2377 // Set it if not NULL
2378 if ( property != NULL )
2380 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2381 double fps = mlt_profile_fps( profile );
2382 property_list *list = self->local;
2383 error = mlt_property_anim_set_double( property, value, fps, list->locale, position, length, keyframe_type );
2384 mlt_properties_do_mirror( self, name );
2387 mlt_events_fire( self, "property-changed", name, NULL );
2392 /** Get the animation associated to the name.
2394 * \public \memberof mlt_properties_s
2395 * \param self a properties list
2396 * \param name the property to get
2397 * \return The animation object or NULL if the property has no animation
2400 mlt_animation mlt_properties_get_animation( mlt_properties self, const char *name )
2402 mlt_property value = mlt_properties_find( self, name );
2403 return value == NULL ? NULL : mlt_property_get_animation( value );
2406 /** Set a property to a rectangle value.
2408 * \public \memberof mlt_properties_s
2409 * \param self a properties list
2410 * \param name the property to set
2411 * \param value the rectangle
2412 * \return true if error
2415 extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value )
2419 if ( !self || !name ) return error;
2421 // Fetch the property to work with
2422 mlt_property property = mlt_properties_fetch( self, name );
2424 // Set it if not NULL
2425 if ( property != NULL )
2427 error = mlt_property_set_rect( property, value );
2428 mlt_properties_do_mirror( self, name );
2431 mlt_events_fire( self, "property-changed", name, NULL );
2436 /** Get a rectangle associated to the name.
2438 * \public \memberof mlt_properties_s
2439 * \param self a properties list
2440 * \param name the property to get
2441 * \return the rectangle value, the rectangle fields will be DBL_MIN if not found
2444 extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char* name )
2446 property_list *list = self->local;
2447 mlt_property value = mlt_properties_find( self, name );
2448 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
2449 return value == NULL ? rect : mlt_property_get_rect( value, list->locale );
2452 /** Set a property to a rectangle value at a frame position.
2454 * \public \memberof mlt_properties_s
2455 * \param self a properties list
2456 * \param name the property to set
2457 * \param value the rectangle
2458 * \param position the frame number
2459 * \param length the maximum number of frames when interpreting negative keyframe times,
2460 * <=0 if you don't care or need that
2461 * \param keyframe_type the interpolation method for this keyframe
2462 * \return true if error
2465 extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_rect value,
2466 int position, int length , mlt_keyframe_type keyframe_type )
2470 if ( !self || !name ) return error;
2472 // Fetch the property to work with
2473 mlt_property property = mlt_properties_fetch( self, name );
2475 // Set it if not NULL
2476 if ( property != NULL )
2478 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2479 double fps = mlt_profile_fps( profile );
2480 property_list *list = self->local;
2481 error = mlt_property_anim_set_rect( property, value, fps, list->locale, position, length, keyframe_type );
2482 mlt_properties_do_mirror( self, name );
2485 mlt_events_fire( self, "property-changed", name, NULL );
2490 /** Get a rectangle associated to the name at a frame position.
2492 * \public \memberof mlt_properties_s
2493 * \param self a properties list
2494 * \param name the property to get
2495 * \param position the frame number
2496 * \param length the maximum number of frames when interpreting negative keyframe times,
2497 * <=0 if you don't care or need that
2498 * \return the rectangle value, the rectangle fields will be DBL_MIN if not found
2501 extern mlt_rect mlt_properties_anim_get_rect( mlt_properties self, const char *name, int position, int length )
2503 mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2504 double fps = mlt_profile_fps( profile );
2505 property_list *list = self->local;
2506 mlt_property value = mlt_properties_find( self, name );
2507 mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN };
2508 return value == NULL ? rect : mlt_property_anim_get_rect( value, fps, list->locale, position, length );