X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fframework%2Fmlt_properties.c;h=2a37ab4d9f84613752bb5288874114d781dc5aa6;hb=1aa26da9547caaa99cf76ad28e1c609a75a3f554;hp=cf9e522c4c0a34702ccc67cf6b606788e7af25bd;hpb=cddee0085dfff8fc8600fe1940cccadbc024de9b;p=mlt diff --git a/src/framework/mlt_properties.c b/src/framework/mlt_properties.c index cf9e522c..2a37ab4d 100644 --- a/src/framework/mlt_properties.c +++ b/src/framework/mlt_properties.c @@ -1,8 +1,9 @@ /** * \file mlt_properties.c * \brief Properties class definition + * \see mlt_properties_s * - * Copyright (C) 2003-2008 Ushodaya Enterprises Limited + * Copyright (C) 2003-2013 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * @@ -21,9 +22,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +// For strtod_l +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include "mlt_properties.h" #include "mlt_property.h" #include "mlt_deque.h" +#include "mlt_log.h" +#include "mlt_factory.h" #include #include @@ -33,7 +41,12 @@ #include #include #include +#include +#include +#include +#include +#define PRESETS_DIR "/presets" /** \brief private implementation of the property list */ @@ -47,6 +60,7 @@ typedef struct mlt_properties mirror; int ref_count; pthread_mutex_t mutex; + locale_t locale; } property_list; @@ -62,14 +76,14 @@ static int properties_destroyed = 0; * * This does allocate its ::property_list, and it adds a reference count. * \public \memberof mlt_properties_s - * \param this the properties structure to initialize + * \param self the properties structure to initialize * \param child an opaque pointer to a subclass object * \return true if failed */ -int mlt_properties_init( mlt_properties this, void *child ) +int mlt_properties_init( mlt_properties self, void *child ) { - if ( this != NULL ) + if ( self != NULL ) { #ifdef _MLT_PROPERTY_CHECKS_ // Increment number of properties created @@ -77,21 +91,21 @@ int mlt_properties_init( mlt_properties this, void *child ) #endif // NULL all methods - memset( this, 0, sizeof( struct mlt_properties_s ) ); + memset( self, 0, sizeof( struct mlt_properties_s ) ); // Assign the child of the object - this->child = child; + self->child = child; // Allocate the local structure - this->local = calloc( sizeof( property_list ), 1 ); + self->local = calloc( 1, sizeof( property_list ) ); // Increment the ref count - ( ( property_list * )this->local )->ref_count = 1; - pthread_mutex_init( &( ( property_list * )this->local )->mutex, NULL );; + ( ( property_list * )self->local )->ref_count = 1; + pthread_mutex_init( &( ( property_list * )self->local )->mutex, NULL );; } // Check that initialisation was successful - return this != NULL && this->local == NULL; + return self != NULL && self->local == NULL; } /** Create a properties object. @@ -105,13 +119,112 @@ int mlt_properties_init( mlt_properties this, void *child ) mlt_properties mlt_properties_new( ) { // Construct a standalone properties object - mlt_properties this = calloc( sizeof( struct mlt_properties_s ), 1 ); + mlt_properties self = calloc( 1, sizeof( struct mlt_properties_s ) ); - // Initialise this - mlt_properties_init( this, NULL ); + // Initialise self + mlt_properties_init( self, NULL ); // Return the pointer - return this; + return self; +} + +/** Set the numeric locale used for string/double conversions. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param locale the locale name + * \return true if error + */ + +int mlt_properties_set_lcnumeric( mlt_properties self, const char *locale ) +{ + int error = 0; + + if ( self && locale ) + { + property_list *list = self->local; + +#if defined(__linux__) || defined(__DARWIN__) + if ( list->locale ) + freelocale( list->locale ); + list->locale = newlocale( LC_NUMERIC_MASK, locale, NULL ); +#endif + error = list->locale == NULL; + } + else + error = 1; + + return error; +} + +/** Get the numeric locale for this properties object. + * + * Do not free the result. + * \public \memberof mlt_properties_s + * \param self a properties list + * \return the locale name if this properties has a specific locale it is using, NULL otherwise + */ + +const char* mlt_properties_get_lcnumeric( mlt_properties self ) +{ + property_list *list = self->local; + const char *result = NULL; + + if ( list->locale ) + { +#if defined(__DARWIN__) + result = querylocale( LC_NUMERIC, list->locale ); +#elif defined(__linux__) + result = list->locale->__names[ LC_NUMERIC ]; +#else + // TODO: not yet sure what to do on other platforms +#endif + } + return result; +} + +static int load_properties( mlt_properties self, const char *filename ) +{ + // Open the file + FILE *file = fopen( filename, "r" ); + + // Load contents of file + if ( file != NULL ) + { + // Temp string + char temp[ 1024 ]; + char last[ 1024 ] = ""; + + // Read each string from the file + while( fgets( temp, 1024, file ) ) + { + // Chomp the new line character from the string + int x = strlen( temp ) - 1; + if ( temp[x] == '\n' || temp[x] == '\r' ) + temp[x] = '\0'; + + // Check if the line starts with a . + if ( temp[ 0 ] == '.' ) + { + char temp2[ 1024 ]; + sprintf( temp2, "%s%s", last, temp ); + strcpy( temp, temp2 ); + } + else if ( strchr( temp, '=' ) ) + { + strcpy( last, temp ); + *( strchr( last, '=' ) ) = '\0'; + } + + // Parse and set the property + if ( strcmp( temp, "" ) && temp[ 0 ] != '#' ) + mlt_properties_parse( self, temp ); + } + + // Close the file + fclose( file ); + } + return file? 0 : errno; } /** Create a properties object by reading a .properties text file. @@ -119,58 +232,91 @@ mlt_properties mlt_properties_new( ) * Free the properties object with mlt_properties_close(). * \deprecated Please start using mlt_properties_parse_yaml(). * \public \memberof mlt_properties_s - * \param filename a string contain the absolute file name + * \param filename the absolute file name * \return a new properties object */ mlt_properties mlt_properties_load( const char *filename ) { // Construct a standalone properties object - mlt_properties this = mlt_properties_new( ); + mlt_properties self = mlt_properties_new( ); - if ( this != NULL ) - { - // Open the file - FILE *file = fopen( filename, "r" ); + if ( self != NULL ) + load_properties( self, filename ); - // Load contents of file - if ( file != NULL ) - { - // Temp string - char temp[ 1024 ]; - char last[ 1024 ] = ""; + // Return the pointer + return self; +} - // Read each string from the file - while( fgets( temp, 1024, file ) ) - { - // Chomp the string - temp[ strlen( temp ) - 1 ] = '\0'; +/** Set properties from a preset. + * + * Presets are typically installed to $prefix/share/mlt/presets/{type}/{service}/[{profile}/]{name}. + * For example, "/usr/share/mlt/presets/consumer/avformat/dv_ntsc_wide/DVD" + * could be an encoding preset for a widescreen NTSC DVD Video. + * Do not specify the type and service in the preset name parameter; these are + * inferred automatically from the service to which you are applying the preset. + * Using the example above and assuming you are calling this function on the + * avformat consumer, the name passed to the function should simply be DVD. + * Note that the profile portion of the path is optional, but a profile-specific + * preset with the same name as a more generic one is given a higher priority. + * \todo Look in a user-specific location - somewhere in the home directory. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the name of a preset in a well-known location or the explicit path + * \return true if error + */ - // Check if the line starts with a . - if ( temp[ 0 ] == '.' ) - { - char temp2[ 1024 ]; - sprintf( temp2, "%s%s", last, temp ); - strcpy( temp, temp2 ); - } - else if ( strchr( temp, '=' ) ) - { - strcpy( last, temp ); - *( strchr( last, '=' ) ) = '\0'; - } +int mlt_properties_preset( mlt_properties self, const char *name ) +{ + struct stat stat_buff; - // Parse and set the property - if ( strcmp( temp, "" ) && temp[ 0 ] != '#' ) - mlt_properties_parse( this, temp ); - } + // validate input + if ( !( self && name && strlen( name ) ) ) + return 1; - // Close the file - fclose( file ); + // See if name is an explicit file + if ( ! stat( name, &stat_buff ) ) + { + return load_properties( self, name ); + } + else + { + // Look for profile-specific preset before a generic one. + char *data = getenv( "MLT_PRESETS_PATH" ); + const char *type = mlt_properties_get( self, "mlt_type" ); + const char *service = mlt_properties_get( self, "mlt_service" ); + const char *profile = mlt_environment( "MLT_PROFILE" ); + int error = 0; + + if ( data ) + { + data = strdup( data ); + } + else + { + data = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + strlen( PRESETS_DIR ) + 1 ); + strcpy( data, mlt_environment( "MLT_DATA" ) ); + strcat( data, PRESETS_DIR ); + } + if ( data && type && service ) + { + char *path = malloc( 5 + strlen(name) + strlen(data) + strlen(type) + strlen(service) + ( profile? strlen(profile) : 0 ) ); + sprintf( path, "%s/%s/%s/%s/%s", data, type, service, profile, name ); + if ( load_properties( self, path ) ) + { + sprintf( path, "%s/%s/%s/%s", data, type, service, name ); + error = load_properties( self, path ); + } + free( path ); + } + else + { + error = 1; } + free( data ); + return error; } - - // Return the pointer - return this; } /** Generate a hash key. @@ -182,29 +328,29 @@ mlt_properties mlt_properties_load( const char *filename ) static inline int generate_hash( const char *name ) { - int hash = 0; - int i = 1; + unsigned int hash = 5381; while ( *name ) - hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199; - return hash; + hash = hash * 33 + (unsigned int) ( *name ++ ); + return hash % 199; } -/** Copy a serializable property to properties list that is mirroring this one. +/** Copy a serializable property to a properties list that is mirroring this one. * - * Special case - when a container (such as fezzik) is protecting another + * Special case - when a container (such as loader) is protecting another * producer, we need to ensure that properties are passed through to the * real producer. * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the name of the property to copy */ -static inline void mlt_properties_do_mirror( mlt_properties this, const char *name ) +static inline void mlt_properties_do_mirror( mlt_properties self, const char *name ) { - property_list *list = this->local; + if ( !self ) return; + property_list *list = self->local; if ( list->mirror != NULL ) { - char *value = mlt_properties_get( this, name ); + char *value = mlt_properties_get( self, name ); if ( value != NULL ) mlt_properties_set( list->mirror, name, value ); } @@ -213,16 +359,16 @@ static inline void mlt_properties_do_mirror( mlt_properties this, const char *na /** Increment the reference count. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the new reference count */ -int mlt_properties_inc_ref( mlt_properties this ) +int mlt_properties_inc_ref( mlt_properties self ) { int result = 0; - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; pthread_mutex_lock( &list->mutex ); result = ++ list->ref_count; pthread_mutex_unlock( &list->mutex ); @@ -233,16 +379,16 @@ int mlt_properties_inc_ref( mlt_properties this ) /** Decrement the reference count. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the new reference count */ -int mlt_properties_dec_ref( mlt_properties this ) +int mlt_properties_dec_ref( mlt_properties self ) { int result = 0; - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; pthread_mutex_lock( &list->mutex ); result = -- list->ref_count; pthread_mutex_unlock( &list->mutex ); @@ -253,15 +399,15 @@ int mlt_properties_dec_ref( mlt_properties this ) /** Get the reference count. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the current reference count */ -int mlt_properties_ref_count( mlt_properties this ) +int mlt_properties_ref_count( mlt_properties self ) { - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; return list->ref_count; } return 0; @@ -273,25 +419,27 @@ int mlt_properties_ref_count( mlt_properties this ) * call this before setting the properties that you wish to copy. * \public \memberof mlt_properties_s * \param that the properties which will receive copies of the properties as they are set. - * \param this the properties to mirror + * \param self the properties to mirror */ -void mlt_properties_mirror( mlt_properties this, mlt_properties that ) +void mlt_properties_mirror( mlt_properties self, mlt_properties that ) { - property_list *list = this->local; + if ( !self ) return; + property_list *list = self->local; list->mirror = that; } /** Copy all serializable properties to another properties list. * * \public \memberof mlt_properties_s - * \param this The properties to copy to + * \param self The properties to copy to * \param that The properties to copy from - * \return false + * \return true if error */ -int mlt_properties_inherit( mlt_properties this, mlt_properties that ) +int mlt_properties_inherit( mlt_properties self, mlt_properties that ) { + if ( !self || !that ) return 1; int count = mlt_properties_count( that ); int i = 0; for ( i = 0; i < count; i ++ ) @@ -300,7 +448,7 @@ int mlt_properties_inherit( mlt_properties this, mlt_properties that ) if ( value != NULL ) { char *name = mlt_properties_get_name( that, i ); - mlt_properties_set( this, name, value ); + mlt_properties_set( self, name, value ); } } return 0; @@ -308,15 +456,19 @@ int mlt_properties_inherit( mlt_properties this, mlt_properties that ) /** Pass all serializable properties that match a prefix to another properties object * + * \warning The prefix is stripped from the name when it is set on the \p self properties list! + * For example a property named "foo.bar" will match prefix "foo.", but the property + * will be named simply "bar" on the receiving properties object. * \public \memberof mlt_properties_s - * \param this the properties to copy to + * \param self the properties to copy to * \param that The properties to copy from * \param prefix the property names to match (required) - * \return false + * \return true if error */ -int mlt_properties_pass( mlt_properties this, mlt_properties that, const char *prefix ) +int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix ) { + if ( !self || !that ) return 1; int count = mlt_properties_count( that ); int length = strlen( prefix ); int i = 0; @@ -327,7 +479,7 @@ int mlt_properties_pass( mlt_properties this, mlt_properties that, const char *p { char *value = mlt_properties_get_value( that, i ); if ( value != NULL ) - mlt_properties_set( this, name + length, value ); + mlt_properties_set( self, name + length, value ); } } return 0; @@ -336,18 +488,21 @@ int mlt_properties_pass( mlt_properties this, mlt_properties that, const char *p /** Locate a property by name. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to lookup by name * \return the property or NULL for failure */ -static inline mlt_property mlt_properties_find( mlt_properties this, const char *name ) +static inline mlt_property mlt_properties_find( mlt_properties self, const char *name ) { - property_list *list = this->local; + if ( !self || !name ) return NULL; + property_list *list = self->local; mlt_property value = NULL; int key = generate_hash( name ); - int i = list->hash[ key ] - 1; + mlt_properties_lock( self ); + + int i = list->hash[ key ] - 1; if ( i >= 0 ) { // Check if we're hashed @@ -361,6 +516,7 @@ static inline mlt_property mlt_properties_find( mlt_properties this, const char if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) ) value = list->value[ i ]; } + mlt_properties_unlock( self ); return value; } @@ -368,15 +524,18 @@ static inline mlt_property mlt_properties_find( mlt_properties this, const char /** Add a new property. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the name of the new property * \return the new property */ -static mlt_property mlt_properties_add( mlt_properties this, const char *name ) +static mlt_property mlt_properties_add( mlt_properties self, const char *name ) { - property_list *list = this->local; + property_list *list = self->local; int key = generate_hash( name ); + mlt_property result; + + mlt_properties_lock( self ); // Check that we have space and resize if necessary if ( list->count == list->size ) @@ -395,25 +554,29 @@ static mlt_property mlt_properties_add( mlt_properties this, const char *name ) list->hash[ key ] = list->count + 1; // Return and increment count accordingly - return list->value[ list->count ++ ]; + result = list->value[ list->count ++ ]; + + mlt_properties_unlock( self ); + + return result; } /** Fetch a property by name and add one if not found. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to lookup or add * \return the property */ -static mlt_property mlt_properties_fetch( mlt_properties this, const char *name ) +static mlt_property mlt_properties_fetch( mlt_properties self, const char *name ) { // Try to find an existing property first - mlt_property property = mlt_properties_find( this, name ); + mlt_property property = mlt_properties_find( self, name ); // If it wasn't found, create one if ( property == NULL ) - property = mlt_properties_add( this, name ); + property = mlt_properties_add( self, name ); // Return the property return property; @@ -423,19 +586,19 @@ static mlt_property mlt_properties_fetch( mlt_properties this, const char *name * * \public \memberof mlt_properties_s * \author Zach - * \param this the properties to copy to + * \param self the properties to copy to * \param that the properties to copy from * \param name the name of the property to copy */ -void mlt_properties_pass_property( mlt_properties this, mlt_properties that, const char *name ) +void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name ) { // Make sure the source property isn't null. mlt_property that_prop = mlt_properties_find( that, name ); if( that_prop == NULL ) return; - mlt_property_pass( mlt_properties_fetch( this, name ), that_prop ); + mlt_property_pass( mlt_properties_fetch( self, name ), that_prop ); } /** Copy all properties specified in a comma-separated list to another properties list. @@ -443,18 +606,19 @@ void mlt_properties_pass_property( mlt_properties this, mlt_properties that, con * White space is also a delimiter. * \public \memberof mlt_properties_s * \author Zach - * \param this the properties to copy to + * \param self the properties to copy to * \param that the properties to copy from * \param list a delimited list of property names - * \return false + * \return true if error */ -int mlt_properties_pass_list( mlt_properties this, mlt_properties that, const char *list ) +int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list ) { + if ( !self || !that || !list ) return 1; char *props = strdup( list ); char *ptr = props; - char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines + const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines int count, done = 0; while( !done ) @@ -466,10 +630,11 @@ int mlt_properties_pass_list( mlt_properties this, mlt_properties that, const ch else ptr[count] = '\0'; // Make it a real string - mlt_properties_pass_property( this, that, ptr ); + mlt_properties_pass_property( self, that, ptr ); ptr += count + 1; - ptr += strspn( ptr, delim ); + if ( !done ) + ptr += strspn( ptr, delim ); } free( props ); @@ -479,36 +644,45 @@ int mlt_properties_pass_list( mlt_properties this, mlt_properties that, const ch /** Set a property to a string. + * + * The property name "properties" is reserved to load the preset in \p value. + * When the value begins with '@' then it is interpreted as a very simple math + * expression containing only the +, -, *, and / operators. + * The event "property-changed" is fired after the property has been set. * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the property's new value * \return true if error */ -int mlt_properties_set( mlt_properties this, const char *name, const char *value ) +int mlt_properties_set( mlt_properties self, const char *name, const char *value ) { int error = 1; + if ( !self || !name ) return error; + // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property == NULL ) { - fprintf( stderr, "Whoops - %s not found (should never occur)\n", name ); + mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name ); } else if ( value == NULL ) { error = mlt_property_set_string( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } else if ( *value != '@' ) { error = mlt_property_set_string( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); + if ( !strcmp( name, "properties" ) ) + mlt_properties_preset( self, value ); } else if ( value[ 0 ] == '@' ) { @@ -530,9 +704,19 @@ int mlt_properties_set( mlt_properties this, const char *name, const char *value // Determine the value if ( isdigit( id[ 0 ] ) ) - current = atof( id ); + { +#if defined(__GLIBC__) || defined(__DARWIN__) + property_list *list = self->local; + if ( list->locale ) + current = strtod_l( id, NULL, list->locale ); + else +#endif + current = strtod( id, NULL ); + } else - current = mlt_properties_get_double( this, id ); + { + current = mlt_properties_get_double( self, id ); + } // Apply the operation switch( op ) @@ -556,10 +740,10 @@ int mlt_properties_set( mlt_properties this, const char *name, const char *value } error = mlt_property_set_double( property, total ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -568,16 +752,16 @@ int mlt_properties_set( mlt_properties this, const char *name, const char *value * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the string value to set or NULL to use the default * \param def the default string if value is NULL * \return true if error */ -int mlt_properties_set_or_default( mlt_properties this, const char *name, const char *value, const char *def ) +int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def ) { - return mlt_properties_set( this, name, value == NULL ? def : value ); + return mlt_properties_set( self, name, value == NULL ? def : value ); } /** Get a string value by name. @@ -585,29 +769,36 @@ int mlt_properties_set_or_default( mlt_properties this, const char *name, const * Do not free the returned string. It's lifetime is controlled by the property * and this properties object. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the property's string value or NULL if it does not exist */ -char *mlt_properties_get( mlt_properties this, const char *name ) +char *mlt_properties_get( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); - return value == NULL ? NULL : mlt_property_get_string( value ); + char *result = NULL; + mlt_property value = mlt_properties_find( self, name ); + if ( value ) + { + property_list *list = self->local; + result = mlt_property_get_string_l( value, list->locale ); + } + return result; } /** Get a property name by index. * * Do not free the returned string. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param index the numeric index of the property * \return the name of the property or NULL if index is out of range */ -char *mlt_properties_get_name( mlt_properties this, int index ) +char *mlt_properties_get_name( mlt_properties self, int index ) { - property_list *list = this->local; + if ( !self ) return NULL; + property_list *list = self->local; if ( index >= 0 && index < list->count ) return list->name[ index ]; return NULL; @@ -617,16 +808,17 @@ char *mlt_properties_get_name( mlt_properties this, int index ) * * Do not free the returned string. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param index the numeric index of the property * \return the property value as a string or NULL if the index is out of range */ -char *mlt_properties_get_value( mlt_properties this, int index ) +char *mlt_properties_get_value( mlt_properties self, int index ) { - property_list *list = this->local; + if ( !self ) return NULL; + property_list *list = self->local; if ( index >= 0 && index < list->count ) - return mlt_property_get_string( list->value[ index ] ); + return mlt_property_get_string_l( list->value[ index ], list->locale ); return NULL; } @@ -635,14 +827,15 @@ char *mlt_properties_get_value( mlt_properties this, int index ) * Do not free the returned pointer if you supplied a destructor function when you * set this property. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param index the numeric index of the property - * \param size the size of the binary data in bytes or NULL if the index is out of range + * \param[out] size the size of the binary data in bytes or NULL if the index is out of range */ -void *mlt_properties_get_data_at( mlt_properties this, int index, int *size ) +void *mlt_properties_get_data_at( mlt_properties self, int index, int *size ) { - property_list *list = this->local; + if ( !self ) return NULL; + property_list *list = self->local; if ( index >= 0 && index < list->count ) return mlt_property_get_data( list->value[ index ], size ); return NULL; @@ -651,26 +844,28 @@ void *mlt_properties_get_data_at( mlt_properties this, int index, int *size ) /** Return the number of items in the list. * * \public \memberof mlt_properties_s - * \param this a properties list - * \return the number of property objects + * \param self a properties list + * \return the number of property objects or -1 if error */ -int mlt_properties_count( mlt_properties this ) +int mlt_properties_count( mlt_properties self ) { - property_list *list = this->local; + if ( !self ) return -1; + property_list *list = self->local; return list->count; } /** Set a value by parsing a name=value string. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param namevalue a string containing name and value delimited by '=' * \return true if there was an error */ -int mlt_properties_parse( mlt_properties this, const char *namevalue ) +int mlt_properties_parse( mlt_properties self, const char *namevalue ) { + if ( !self ) return 1; char *name = strdup( namevalue ); char *value = NULL; int error = 0; @@ -697,7 +892,7 @@ int mlt_properties_parse( mlt_properties this, const char *namevalue ) value = strdup( "" ); } - error = mlt_properties_set( this, name, value ); + error = mlt_properties_set( self, name, value ); free( name ); free( value ); @@ -708,41 +903,51 @@ int mlt_properties_parse( mlt_properties this, const char *namevalue ) /** Get an integer associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return The integer value, 0 if not found (which may also be a legitimate value) */ -int mlt_properties_get_int( mlt_properties this, const char *name ) +int mlt_properties_get_int( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); - return value == NULL ? 0 : mlt_property_get_int( value ); + int result = 0; + mlt_property value = mlt_properties_find( self, name ); + if ( value ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + result = mlt_property_get_int( value, fps, list->locale ); + } + return result; } /** Set a property to an integer value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the integer * \return true if error */ -int mlt_properties_set_int( mlt_properties this, const char *name, int value ) +int mlt_properties_set_int( mlt_properties self, const char *name, int value ) { int error = 1; + if ( !self || !name ) return error; + // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_int( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -750,41 +955,43 @@ int mlt_properties_set_int( mlt_properties this, const char *name, int value ) /** Get a 64-bit integer associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the integer value, 0 if not found (which may also be a legitimate value) */ -int64_t mlt_properties_get_int64( mlt_properties this, const char *name ) +int64_t mlt_properties_get_int64( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_get_int64( value ); } /** Set a property to a 64-bit integer value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the integer * \return true if error */ -int mlt_properties_set_int64( mlt_properties this, const char *name, int64_t value ) +int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value ) { int error = 1; + if ( !self || !name ) return error; + // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_int64( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -792,41 +999,51 @@ int mlt_properties_set_int64( mlt_properties this, const char *name, int64_t val /** Get a floating point value associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the floating point, 0 if not found (which may also be a legitimate value) */ -double mlt_properties_get_double( mlt_properties this, const char *name ) +double mlt_properties_get_double( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); - return value == NULL ? 0 : mlt_property_get_double( value ); + double result = 0; + mlt_property value = mlt_properties_find( self, name ); + if ( value ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + result = mlt_property_get_double( value, fps, list->locale ); + } + return result; } /** Set a property to a floating point value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the floating point value * \return true if error */ -int mlt_properties_set_double( mlt_properties this, const char *name, double value ) +int mlt_properties_set_double( mlt_properties self, const char *name, double value ) { int error = 1; + if ( !self || !name ) return error; + // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_double( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -834,41 +1051,51 @@ int mlt_properties_set_double( mlt_properties this, const char *name, double val /** Get a position value associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the position, 0 if not found (which may also be a legitimate value) */ -mlt_position mlt_properties_get_position( mlt_properties this, const char *name ) +mlt_position mlt_properties_get_position( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); - return value == NULL ? 0 : mlt_property_get_position( value ); + mlt_position result = 0; + mlt_property value = mlt_properties_find( self, name ); + if ( value ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + result = mlt_property_get_position( value, fps, list->locale ); + } + return result; } /** Set a property to a position value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \param value the position * \return true if error */ -int mlt_properties_set_position( mlt_properties this, const char *name, mlt_position value ) +int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value ) { int error = 1; + if ( !self || !name ) return error; + // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_position( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -878,41 +1105,43 @@ int mlt_properties_set_position( mlt_properties this, const char *name, mlt_posi * Do not free the returned pointer if you supplied a destructor function * when you set this property. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get - * \param length The size of the binary data in bytes, if available (often it is not, you should know) + * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know) */ -void *mlt_properties_get_data( mlt_properties this, const char *name, int *length ) +void *mlt_properties_get_data( mlt_properties self, const char *name, int *length ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? NULL : mlt_property_get_data( value, length ); } /** Store binary data as a property. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value an opaque pointer to binary data * \param length the size of the binary data in bytes (optional) - * \param destroy a function to dellacate the binary data when the property is closed (optional) + * \param destroy a function to deallocate the binary data when the property is closed (optional) * \param serialise a function that can serialize the binary data as text (optional) * \return true if error */ -int mlt_properties_set_data( mlt_properties this, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ) +int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ) { int error = 1; + if ( !self || !name ) return error; + // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) error = mlt_property_set_data( property, value, length, destroy, serialise ); - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -920,22 +1149,23 @@ int mlt_properties_set_data( mlt_properties this, const char *name, void *value, /** Rename a property. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param source the property to rename * \param dest the new name * \return true if the name is already in use */ -int mlt_properties_rename( mlt_properties this, const char *source, const char *dest ) +int mlt_properties_rename( mlt_properties self, const char *source, const char *dest ) { - mlt_property value = mlt_properties_find( this, dest ); + mlt_property value = mlt_properties_find( self, dest ); if ( value == NULL ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; // Locate the item + mlt_properties_lock( self ); for ( i = 0; i < list->count; i ++ ) { if ( !strcmp( list->name[ i ], source ) ) @@ -946,6 +1176,7 @@ int mlt_properties_rename( mlt_properties this, const char *source, const char * break; } } + mlt_properties_unlock( self ); } return value != NULL; @@ -954,41 +1185,43 @@ int mlt_properties_rename( mlt_properties this, const char *source, const char * /** Dump the properties to a file handle. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param output a file handle */ -void mlt_properties_dump( mlt_properties this, FILE *output ) +void mlt_properties_dump( mlt_properties self, FILE *output ) { - property_list *list = this->local; + if ( !self || !output ) return; + property_list *list = self->local; int i = 0; for ( i = 0; i < list->count; i ++ ) - if ( mlt_properties_get( this, list->name[ i ] ) != NULL ) - fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) ); + if ( mlt_properties_get( self, list->name[ i ] ) != NULL ) + fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) ); } /** Output the properties to a file handle. * * This version includes reference counts and does not put each property on a new line. * \public \memberof mlt_properties_s - * \param this a properties pointer + * \param self a properties pointer * \param title a string to preface the output * \param output a file handle */ -void mlt_properties_debug( mlt_properties this, const char *title, FILE *output ) +void mlt_properties_debug( mlt_properties self, const char *title, FILE *output ) { + if ( !self || !output ) return; if ( output == NULL ) output = stderr; fprintf( output, "%s: ", title ); - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; fprintf( output, "[ ref=%d", list->ref_count ); for ( i = 0; i < list->count; i ++ ) - if ( mlt_properties_get( this, list->name[ i ] ) != NULL ) - fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) ); + if ( mlt_properties_get( self, list->name[ i ] ) != NULL ) + fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) ); else - fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( this, list->name[ i ], NULL ) ); + fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) ); fprintf( output, " ]" ); } fprintf( output, "\n" ); @@ -998,18 +1231,19 @@ void mlt_properties_debug( mlt_properties this, const char *title, FILE *output * * This uses the dump format - one line per property. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param filename the name of a file to create or overwrite * \return true if there was an error */ -int mlt_properties_save( mlt_properties this, const char *filename ) +int mlt_properties_save( mlt_properties self, const char *filename ) { int error = 1; + if ( !self || !filename ) return error; FILE *f = fopen( filename, "w" ); if ( f != NULL ) { - mlt_properties_dump( this, f ); + mlt_properties_dump( self, f ); fclose( f ); error = 0; } @@ -1064,14 +1298,14 @@ static int mlt_fnmatch( const char *wild, const char *file ) /** Compare the string or serialized value of two properties. * * \private \memberof mlt_properties_s - * \param this a property + * \param self a property * \param that a property - * \return < 0 if 'this' less than 'that', 0 if equal, or > 0 if 'this' is greater than 'that' + * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that */ -static int mlt_compare( const void *this, const void *that ) +static int mlt_compare( const void *self, const void *that ) { - return strcmp( mlt_property_get_string( *( mlt_property * )this ), mlt_property_get_string( *( mlt_property * )that ) ); + return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) ); } /** Get the contents of a directory. @@ -1080,14 +1314,14 @@ static int mlt_compare( const void *this, const void *that ) * Entries in the list have a numeric name (running from 0 to count - 1). Only values change * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc). * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param dirname the name of the directory * \param pattern a wildcard pattern to filter the directory listing * \param sort Do you want to sort the directory listing? * \return the number of items in the directory listing */ -int mlt_properties_dir_list( mlt_properties this, const char *dirname, const char *pattern, int sort ) +int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort ) { DIR *dir = opendir( dirname ); @@ -1098,50 +1332,52 @@ int mlt_properties_dir_list( mlt_properties this, const char *dirname, const cha char fullname[ 1024 ]; while( de != NULL ) { - sprintf( key, "%d", mlt_properties_count( this ) ); + sprintf( key, "%d", mlt_properties_count( self ) ); snprintf( fullname, 1024, "%s/%s", dirname, de->d_name ); if ( pattern == NULL ) - mlt_properties_set( this, key, fullname ); + mlt_properties_set( self, key, fullname ); else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) ) - mlt_properties_set( this, key, fullname ); + mlt_properties_set( self, key, fullname ); de = readdir( dir ); } closedir( dir ); } - if ( sort && mlt_properties_count( this ) ) + if ( sort && mlt_properties_count( self ) ) { - property_list *list = this->local; - qsort( list->value, mlt_properties_count( this ), sizeof( mlt_property ), mlt_compare ); + property_list *list = self->local; + mlt_properties_lock( self ); + qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare ); + mlt_properties_unlock( self ); } - return mlt_properties_count( this ); + return mlt_properties_count( self ); } /** Close a properties object. * * Deallocates the properties object and everything it contains. * \public \memberof mlt_properties_s - * \param this a properties object + * \param self a properties object */ -void mlt_properties_close( mlt_properties this ) +void mlt_properties_close( mlt_properties self ) { - if ( this != NULL && mlt_properties_dec_ref( this ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 ) { - if ( this->close != NULL ) + if ( self->close != NULL ) { - this->close( this->close_object ); + self->close( self->close_object ); } else { - property_list *list = this->local; + property_list *list = self->local; int index = 0; #if _MLT_PROPERTY_CHECKS_ == 1 // Show debug info - mlt_properties_debug( this, "Closing", stderr ); + mlt_properties_debug( self, "Closing", stderr ); #endif #ifdef _MLT_PROPERTY_CHECKS_ @@ -1149,25 +1385,31 @@ void mlt_properties_close( mlt_properties this ) properties_destroyed ++; // Show current stats - these should match when the app is closed - fprintf( stderr, "Created %d, destroyed %d\n", properties_created, properties_destroyed ); + mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed ); #endif // Clean up names and values for ( index = list->count - 1; index >= 0; index -- ) { - free( list->name[ index ] ); mlt_property_close( list->value[ index ] ); + free( list->name[ index ] ); } +#if defined(__linux__) || defined(__DARWIN__) + // Cleanup locale + if ( list->locale ) + freelocale( list->locale ); +#endif + // Clear up the list pthread_mutex_destroy( &list->mutex ); free( list->name ); free( list->value ); free( list ); - // Free this now if this has no child - if ( this->child == NULL ) - free( this ); + // Free self now if self has no child + if ( self->child == NULL ) + free( self ); } } } @@ -1206,7 +1448,8 @@ struct yaml_parser_context { mlt_deque stack; unsigned int level; - unsigned int index; + int index; + mlt_deque index_stack; char block; char *block_name; unsigned int block_indent; @@ -1262,7 +1505,7 @@ static int parse_yaml( yaml_parser context, const char *namevalue ) int error = 0; char *ptr = strchr( name, ':' ); unsigned int indent = ltrim( &name ); - mlt_properties properties = mlt_deque_peek_front( context->stack ); + mlt_properties properties = mlt_deque_peek_back( context->stack ); // Ascending one more levels in the tree if ( indent < context->level ) @@ -1270,8 +1513,11 @@ static int parse_yaml( yaml_parser context, const char *namevalue ) unsigned int i; unsigned int n = ( context->level - indent ) / 2; for ( i = 0; i < n; i++ ) - mlt_deque_pop_front( context->stack ); - properties = mlt_deque_peek_front( context->stack ); + { + mlt_deque_pop_back( context->stack ); + context->index = mlt_deque_pop_back_int( context->index_stack ); + } + properties = mlt_deque_peek_back( context->stack ); context->level = indent; } @@ -1310,9 +1556,11 @@ static int parse_yaml( yaml_parser context, const char *namevalue ) if ( strcmp( ptr, "" ) == 0 ) { mlt_properties child = mlt_properties_new(); + mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) ); mlt_properties_set_data( properties, name, child, 0, ( mlt_destructor )mlt_properties_close, NULL ); - mlt_deque_push_front( context->stack, child ); + mlt_deque_push_back( context->stack, child ); + mlt_deque_push_back_int( context->index_stack, context->index ); context->index = 0; free( name_ ); return error; @@ -1324,10 +1572,12 @@ static int parse_yaml( yaml_parser context, const char *namevalue ) mlt_properties child = mlt_properties_new(); char key[20]; + mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) ); snprintf( key, sizeof(key), "%d", context->index++ ); mlt_properties_set_data( properties, key, child, 0, ( mlt_destructor )mlt_properties_close, NULL ); - mlt_deque_push_front( context->stack, child ); + mlt_deque_push_back( context->stack, child ); + mlt_deque_push_back_int( context->index_stack, context->index ); name ++; context->level += ltrim( &name ) + 1; @@ -1462,6 +1712,9 @@ static int parse_yaml( yaml_parser context, const char *namevalue ) error = mlt_properties_set( properties, name, value ); + if ( !strcmp( name, "LC_NUMERIC" ) ) + mlt_properties_set_lcnumeric( properties, value ); + free( name_ ); free( value ); @@ -1478,9 +1731,9 @@ static int parse_yaml( yaml_parser context, const char *namevalue ) mlt_properties mlt_properties_parse_yaml( const char *filename ) { // Construct a standalone properties object - mlt_properties this = mlt_properties_new( ); + mlt_properties self = mlt_properties_new( ); - if ( this ) + if ( self ) { // Open the file FILE *file = fopen( filename, "r" ); @@ -1492,10 +1745,15 @@ mlt_properties mlt_properties_parse_yaml( const char *filename ) char temp[ 1024 ]; char *ptemp = &temp[ 0 ]; + // Default to LC_NUMERIC = C + mlt_properties_set_lcnumeric( self, "C" ); + // Parser context yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) ); context->stack = mlt_deque_init(); - mlt_deque_push_front( context->stack, this ); + context->index_stack = mlt_deque_init(); + mlt_deque_push_back( context->stack, self ); + mlt_deque_push_back_int( context->index_stack, 0 ); // Read each string from the file while( fgets( temp, 1024, file ) ) @@ -1516,6 +1774,7 @@ mlt_properties mlt_properties_parse_yaml( const char *filename ) // Close the file fclose( file ); mlt_deque_close( context->stack ); + mlt_deque_close( context->index_stack ); if ( context->block_name ) free( context->block_name ); free( context ); @@ -1523,7 +1782,7 @@ mlt_properties mlt_properties_parse_yaml( const char *filename ) } // Return the pointer - return this; + return self; } /* @@ -1533,7 +1792,7 @@ mlt_properties mlt_properties_parse_yaml( const char *filename ) /** How many bytes to grow at a time */ #define STRBUF_GROWTH (1024) -/** \brief Self-growing buffer for building strings +/** \brief Private to mlt_properties_s, a self-growing buffer for building strings * \private */ @@ -1616,6 +1875,23 @@ static inline void indent_yaml( strbuf output, int indent ) strbuf_printf( output, " " ); } +static void strbuf_escape( strbuf output, const char *value, char c ) +{ + char *v = strdup( value ); + char *s = v; + char *found = strchr( s, c ); + + while ( found ) + { + *found = '\0'; + strbuf_printf( output, "%s\\%c", s, c ); + s = found + 1; + found = strchr( s, c ); + } + strbuf_printf( output, "%s", s ); + free( v ); +} + /** Convert a line string into a YAML block literal. * * \private \memberof strbuf_s @@ -1640,20 +1916,21 @@ static void output_yaml_block_literal( strbuf output, const char *value, int ind } indent_yaml( output, indent ); strbuf_printf( output, "%s\n", sol ); + free( v ); } /** Recursively serialize a properties list into a string buffer as YAML Tiny. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param output a string buffer to hold the serialized YAML Tiny * \param indent the number of spaces to indent (for recursion, initialize to 0) - * \param is_parent_sequence Is 'this' properties list really just a sequence (for recursion, initialize to 0)? + * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)? */ -static void serialise_yaml( mlt_properties this, strbuf output, int indent, int is_parent_sequence ) +static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; for ( i = 0; i < list->count; i ++ ) @@ -1662,7 +1939,7 @@ static void serialise_yaml( mlt_properties this, strbuf output, int indent, int // Unfortunately, we do not have run time type identification. mlt_properties child = mlt_property_get_data( list->value[ i ], NULL ); - if ( mlt_properties_is_sequence( this ) ) + if ( mlt_properties_is_sequence( self ) ) { // Ignore hidden/non-serialisable items if ( list->name[ i ][ 0 ] != '_' ) @@ -1672,7 +1949,7 @@ static void serialise_yaml( mlt_properties this, strbuf output, int indent, int strbuf_printf( output, "- " ); // If the value can be represented as a string - const char *value = mlt_properties_get( this, list->name[ i ] ); + const char *value = mlt_properties_get( self, list->name[ i ] ); if ( value && strcmp( value, "" ) ) { // Determine if this is an unfolded block literal @@ -1681,6 +1958,12 @@ static void serialise_yaml( mlt_properties this, strbuf output, int indent, int strbuf_printf( output, "|\n" ); output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) ); } + else if ( strchr( value, ':' ) || strchr( value, '[' ) ) + { + strbuf_printf( output, "\"" ); + strbuf_escape( output, value, '"' ); + strbuf_printf( output, "\"\n", value ); + } else { strbuf_printf( output, "%s\n", value ); @@ -1694,7 +1977,7 @@ static void serialise_yaml( mlt_properties this, strbuf output, int indent, int else { // Assume this is a normal map-oriented properties list - const char *value = mlt_properties_get( this, list->name[ i ] ); + const char *value = mlt_properties_get( self, list->name[ i ] ); // Ignore hidden/non-serialisable items // If the value can be represented as a string @@ -1711,6 +1994,12 @@ static void serialise_yaml( mlt_properties this, strbuf output, int indent, int strbuf_printf( output, "%s: |\n", list->name[ i ] ); output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) ); } + else if ( strchr( value, ':' ) || strchr( value, '[' ) ) + { + strbuf_printf( output, "%s: \"", list->name[ i ] ); + strbuf_escape( output, value, '"' ); + strbuf_printf( output, "\"\n" ); + } else { strbuf_printf( output, "%s: %s\n", list->name[ i ], value ); @@ -1736,17 +2025,486 @@ static void serialise_yaml( mlt_properties this, strbuf output, int indent, int * This operates on properties containing properties as a hierarchical data * structure. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return a string containing YAML Tiny that represents the properties list */ -char *mlt_properties_serialise_yaml( mlt_properties this ) +char *mlt_properties_serialise_yaml( mlt_properties self ) { + if ( !self ) return NULL; + const char *lc_numeric = mlt_properties_get_lcnumeric( self ); strbuf b = strbuf_new(); strbuf_printf( b, "---\n" ); - serialise_yaml( this, b, 0, 0 ); + mlt_properties_set_lcnumeric( self, "C" ); + serialise_yaml( self, b, 0, 0 ); + mlt_properties_set_lcnumeric( self, lc_numeric ); strbuf_printf( b, "...\n" ); char *ret = b->string; strbuf_close( b ); return ret; } + +/** Protect a properties list against concurrent access. + * + * \public \memberof mlt_properties_s + * \param self a properties list + */ + +void mlt_properties_lock( mlt_properties self ) +{ + if ( self ) + pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex ); +} + +/** End protecting a properties list against concurrent access. + * + * \public \memberof mlt_properties_s + * \param self a properties list + */ + +void mlt_properties_unlock( mlt_properties self ) +{ + if ( self ) + pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex ); +} + +/** Get a time string associated to the name. + * + * Do not free the returned string. It's lifetime is controlled by the property. + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \param format the time format that you want + * \return the property's time value or NULL if \p name does not exist or there is no profile + */ + +char *mlt_properties_get_time( mlt_properties self, const char* name, mlt_time_format format ) +{ + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + if ( profile ) + { + double fps = mlt_profile_fps( profile ); + mlt_property value = mlt_properties_find( self, name ); + property_list *list = self->local; + return value == NULL ? NULL : mlt_property_get_time( value, format, fps, list->locale ); + } + return NULL; +} + +/** Convert a frame count to a time string. + * + * Do not free the returned string. It's lifetime is controlled by the property. + * \public \memberof mlt_properties_s + * \param self a properties list + * \param frames the frame count to convert + * \param format the time format that you want + * \return the time string or NULL if error, e.g. there is no profile + */ + +char *mlt_properties_frames_to_time( mlt_properties self, mlt_position frames, mlt_time_format format ) +{ + const char *name = "_mlt_properties_time"; + mlt_properties_set_position( self, name, frames ); + return mlt_properties_get_time( self, name, format ); +} + +/** Convert a time string to a frame count. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param time the time string to convert + * \return a frame count or a negative value if error, e.g. there is no profile + */ + +mlt_position mlt_properties_time_to_frames( mlt_properties self, const char *time ) +{ + const char *name = "_mlt_properties_time"; + mlt_properties_set( self, name, time ); + return mlt_properties_get_position( self, name ); +} + +/** Convert a numeric property to a tuple of color components. + * + * If the property's string is red, green, blue, white, or black, then it + * is converted to the corresponding opaque color tuple. Otherwise, the property + * is fetched as an integer and then converted. + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \return a color structure + */ + +mlt_color mlt_properties_get_color( mlt_properties self, const char* name ) +{ + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + mlt_property value = mlt_properties_find( self, name ); + mlt_color result = { 0xff, 0xff, 0xff, 0xff }; + if ( value ) + { + const char *color = mlt_property_get_string_l( value, list->locale ); + unsigned int color_int = mlt_property_get_int( value, fps, list->locale ); + + if ( !strcmp( color, "red" ) ) + { + result.r = 0xff; + result.g = 0x00; + result.b = 0x00; + } + else if ( !strcmp( color, "green" ) ) + { + result.r = 0x00; + result.g = 0xff; + result.b = 0x00; + } + else if ( !strcmp( color, "blue" ) ) + { + result.r = 0x00; + result.g = 0x00; + result.b = 0xff; + } + else if ( !strcmp( color, "black" ) ) + { + result.r = 0x00; + result.g = 0x00; + result.b = 0x00; + } + else if ( strcmp( color, "white" ) ) + { + result.r = ( color_int >> 24 ) & 0xff; + result.g = ( color_int >> 16 ) & 0xff; + result.b = ( color_int >> 8 ) & 0xff; + result.a = ( color_int ) & 0xff; + } + } + return result; +} + +/** Set a property to an integer value by color. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to set + * \param color the color + * \return true if error + */ + +int mlt_properties_set_color( mlt_properties self, const char *name, mlt_color color ) +{ + int error = 1; + + if ( !self || !name ) return error; + + // Fetch the property to work with + mlt_property property = mlt_properties_fetch( self, name ); + + // Set it if not NULL + if ( property != NULL ) + { + uint32_t value = ( color.r << 24 ) | ( color.g << 16 ) | ( color.b << 8 ) | color.a; + error = mlt_property_set_int( property, value ); + mlt_properties_do_mirror( self, name ); + } + + mlt_events_fire( self, "property-changed", name, NULL ); + + return error; +} + +/** Get a string value by name at a frame position. + * + * Do not free the returned string. It's lifetime is controlled by the property + * and this properties object. + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \return the property's string value or NULL if it does not exist + */ + +char* mlt_properties_anim_get( mlt_properties self, const char *name, int position, int length ) +{ + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + mlt_property value = mlt_properties_find( self, name ); + property_list *list = self->local; + return value == NULL ? NULL : mlt_property_anim_get_string( value, fps, list->locale, position, length ); +} + +/** Set a property to a string at a frame position. + * + * The event "property-changed" is fired after the property has been set. + * + * This makes a copy of the string value you supply. + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to set + * \param value the property's new value + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \return true if error + */ + +int mlt_properties_anim_set( mlt_properties self, const char *name, const char *value, int position, int length ) +{ + int error = 1; + + if ( !self || !name ) return error; + + // Fetch the property to work with + mlt_property property = mlt_properties_fetch( self, name ); + + // Set it if not NULL + if ( property ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + error = mlt_property_anim_set_string( property, value, + fps, list->locale, position, length ); + mlt_properties_do_mirror( self, name ); + } + + mlt_events_fire( self, "property-changed", name, NULL ); + + return error; +} + +/** Get an integer associated to the name at a frame position. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \return the integer value, 0 if not found (which may also be a legitimate value) + */ + +int mlt_properties_anim_get_int( mlt_properties self, const char *name, int position, int length ) +{ + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + mlt_property value = mlt_properties_find( self, name ); + return value == NULL ? 0 : mlt_property_anim_get_int( value, fps, list->locale, position, length ); +} + +/** Set a property to an integer value at a frame position. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to set + * \param value the integer + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \param keyframe_type the interpolation method for this keyframe + * \return true if error + */ + +int mlt_properties_anim_set_int( mlt_properties self, const char *name, int value, + int position, int length, mlt_keyframe_type keyframe_type ) +{ + int error = 1; + + if ( !self || !name ) return error; + + // Fetch the property to work with + mlt_property property = mlt_properties_fetch( self, name ); + + // Set it if not NULL + if ( property != NULL ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + error = mlt_property_anim_set_int( property, value, fps, list->locale, position, length, keyframe_type ); + mlt_properties_do_mirror( self, name ); + } + + mlt_events_fire( self, "property-changed", name, NULL ); + + return error; +} + +/** Get a real number associated to the name at a frame position. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \return the real number, 0 if not found (which may also be a legitimate value) + */ + +double mlt_properties_anim_get_double( mlt_properties self, const char *name, int position, int length ) +{ + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + mlt_property value = mlt_properties_find( self, name ); + return value == NULL ? 0.0 : mlt_property_anim_get_double( value, fps, list->locale, position, length ); +} + +/** Set a property to a real number at a frame position. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to set + * \param value the real number + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \param keyframe_type the interpolation method for this keyframe + * \return true if error + */ + +int mlt_properties_anim_set_double( mlt_properties self, const char *name, double value, + int position, int length, mlt_keyframe_type keyframe_type ) +{ + int error = 1; + + if ( !self || !name ) return error; + + // Fetch the property to work with + mlt_property property = mlt_properties_fetch( self, name ); + + // Set it if not NULL + if ( property != NULL ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + error = mlt_property_anim_set_double( property, value, fps, list->locale, position, length, keyframe_type ); + mlt_properties_do_mirror( self, name ); + } + + mlt_events_fire( self, "property-changed", name, NULL ); + + return error; +} + +/** Get the animation associated to the name. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \return The animation object or NULL if the property has no animation + */ + +mlt_animation mlt_properties_get_animation( mlt_properties self, const char *name ) +{ + mlt_property value = mlt_properties_find( self, name ); + return value == NULL ? NULL : mlt_property_get_animation( value ); +} + +/** Set a property to a rectangle value. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to set + * \param value the rectangle + * \return true if error + */ + +extern int mlt_properties_set_rect( mlt_properties self, const char *name, mlt_rect value ) +{ + int error = 1; + + if ( !self || !name ) return error; + + // Fetch the property to work with + mlt_property property = mlt_properties_fetch( self, name ); + + // Set it if not NULL + if ( property != NULL ) + { + error = mlt_property_set_rect( property, value ); + mlt_properties_do_mirror( self, name ); + } + + mlt_events_fire( self, "property-changed", name, NULL ); + + return error; +} + +/** Get a rectangle associated to the name. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \return the rectangle value, the rectangle fields will be DBL_MIN if not found + */ + +extern mlt_rect mlt_properties_get_rect( mlt_properties self, const char* name ) +{ + property_list *list = self->local; + mlt_property value = mlt_properties_find( self, name ); + mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN }; + return value == NULL ? rect : mlt_property_get_rect( value, list->locale ); +} + +/** Set a property to a rectangle value at a frame position. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to set + * \param value the rectangle + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \param keyframe_type the interpolation method for this keyframe + * \return true if error + */ + +extern int mlt_properties_anim_set_rect( mlt_properties self, const char *name, mlt_rect value, + int position, int length , mlt_keyframe_type keyframe_type ) +{ + int error = 1; + + if ( !self || !name ) return error; + + // Fetch the property to work with + mlt_property property = mlt_properties_fetch( self, name ); + + // Set it if not NULL + if ( property != NULL ) + { + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + error = mlt_property_anim_set_rect( property, value, fps, list->locale, position, length, keyframe_type ); + mlt_properties_do_mirror( self, name ); + } + + mlt_events_fire( self, "property-changed", name, NULL ); + + return error; +} + +/** Get a rectangle associated to the name at a frame position. + * + * \public \memberof mlt_properties_s + * \param self a properties list + * \param name the property to get + * \param position the frame number + * \param length the maximum number of frames when interpreting negative keyframe times, + * <=0 if you don't care or need that + * \return the rectangle value, the rectangle fields will be DBL_MIN if not found + */ + +extern mlt_rect mlt_properties_anim_get_rect( mlt_properties self, const char *name, int position, int length ) +{ + mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL ); + double fps = mlt_profile_fps( profile ); + property_list *list = self->local; + mlt_property value = mlt_properties_find( self, name ); + mlt_rect rect = { DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN, DBL_MIN }; + return value == NULL ? rect : mlt_property_anim_get_rect( value, fps, list->locale, position, length ); +}