From: Dan Dennedy Date: Fri, 13 May 2011 03:12:00 +0000 (-0700) Subject: Presets! X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=46fc89b27e98266757dfb7a55912becef8d419e2;p=mlt Presets! Put property setters in a file and apply them to a service using properties=filename. Alternatively, apply a supplied preset using properties=preset. For example, melt ... -consumer avformat:my.vob properties=DVD. --- diff --git a/Makefile b/Makefile index de66bb74..136171b1 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,8 @@ install: list='$(SUBDIRS)'; \ for subdir in $$list; do \ $(MAKE) DESTDIR=$(DESTDIR) -C $$subdir $@ || exit 1; \ - done; \ -# if test -z "$(DESTDIR)"; then \ -# /sbin/ldconfig -n "$(DESTDIR)$(libdir)" 2> /dev/null || true; \ -# fi + done + cp -R presets "$(DESTDIR)$(prefix)/share/mlt" uninstall: rm -f "$(DESTDIR)$(bindir)"/mlt-config diff --git a/presets/consumer/avformat/dv_ntsc/DVD b/presets/consumer/avformat/dv_ntsc/DVD new file mode 100644 index 00000000..8fad3565 --- /dev/null +++ b/presets/consumer/avformat/dv_ntsc/DVD @@ -0,0 +1,15 @@ +f=dvd +vcodec=mpeg2video +acodec=ac3 +b=6000k +maxrate=9000k +minrate=0 +bufsize=1835008 +packetsize=2048 +muxrate=10080000 +ab=192k +ar=48000 +g=18 +me_range=63 +trellis=1 + diff --git a/presets/consumer/avformat/dv_ntsc_wide/DVD b/presets/consumer/avformat/dv_ntsc_wide/DVD new file mode 100644 index 00000000..8fad3565 --- /dev/null +++ b/presets/consumer/avformat/dv_ntsc_wide/DVD @@ -0,0 +1,15 @@ +f=dvd +vcodec=mpeg2video +acodec=ac3 +b=6000k +maxrate=9000k +minrate=0 +bufsize=1835008 +packetsize=2048 +muxrate=10080000 +ab=192k +ar=48000 +g=18 +me_range=63 +trellis=1 + diff --git a/presets/consumer/avformat/dv_pal/DVD b/presets/consumer/avformat/dv_pal/DVD new file mode 100644 index 00000000..6ce9f519 --- /dev/null +++ b/presets/consumer/avformat/dv_pal/DVD @@ -0,0 +1,15 @@ +f=dvd +vcodec=mpeg2video +acodec=ac3 +b=5000k +maxrate=8000k +minrate=0 +bufsize=1835008 +packetsize=2048 +muxrate=10080000 +ab=192k +ar=48000 +g=15 +me_range=63 +trellis=1 + diff --git a/presets/consumer/avformat/dv_pal_wide/DVD b/presets/consumer/avformat/dv_pal_wide/DVD new file mode 100644 index 00000000..6ce9f519 --- /dev/null +++ b/presets/consumer/avformat/dv_pal_wide/DVD @@ -0,0 +1,15 @@ +f=dvd +vcodec=mpeg2video +acodec=ac3 +b=5000k +maxrate=8000k +minrate=0 +bufsize=1835008 +packetsize=2048 +muxrate=10080000 +ab=192k +ar=48000 +g=15 +me_range=63 +trellis=1 + diff --git a/setenv b/setenv index f2f668dd..162230b3 100644 --- a/setenv +++ b/setenv @@ -4,6 +4,7 @@ export MLT_REPOSITORY=`pwd`/src/modules export MLT_DATA=`pwd`/src/modules export MLT_PROFILES_PATH=`pwd`/profiles +export MLT_PRESETS_PATH=`pwd`/presets export LD_LIBRARY_PATH=\ `pwd`/src/framework:\ diff --git a/src/framework/mlt_properties.c b/src/framework/mlt_properties.c index a8c2d865..fd674e1a 100644 --- a/src/framework/mlt_properties.c +++ b/src/framework/mlt_properties.c @@ -26,6 +26,7 @@ #include "mlt_property.h" #include "mlt_deque.h" #include "mlt_log.h" +#include "mlt_factory.h" #include #include @@ -35,7 +36,8 @@ #include #include #include - +#include +#include /** \brief private implementation of the property list */ @@ -116,12 +118,54 @@ mlt_properties mlt_properties_new( ) return self; } +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 string + temp[ strlen( temp ) - 1 ] = '\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. * * 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 */ @@ -131,48 +175,81 @@ mlt_properties mlt_properties_load( const char *filename ) mlt_properties self = mlt_properties_new( ); if ( self != NULL ) - { - // Open the file - FILE *file = fopen( filename, "r" ); + 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( self, 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" ) ) + 9 ); + strcpy( data, mlt_environment( "MLT_DATA" ) ); + strcat( data, "/presets" ); + } + 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 self; } /** Generate a hash key. @@ -491,6 +568,11 @@ int mlt_properties_pass_list( mlt_properties self, 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 @@ -521,6 +603,8 @@ int mlt_properties_set( mlt_properties self, const char *name, const char *value { error = mlt_property_set_string( property, value ); mlt_properties_do_mirror( self, name ); + if ( !strcmp( name, "properties" ) ) + mlt_properties_preset( self, value ); } else if ( value[ 0 ] == '@' ) { diff --git a/src/framework/mlt_properties.h b/src/framework/mlt_properties.h index 55f9b0d6..5e17b150 100644 --- a/src/framework/mlt_properties.h +++ b/src/framework/mlt_properties.h @@ -48,6 +48,7 @@ struct mlt_properties_s extern int mlt_properties_init( mlt_properties, void *child ); extern mlt_properties mlt_properties_new( ); extern mlt_properties mlt_properties_load( const char *file ); +extern int mlt_properties_preset( mlt_properties self, const char *name ); extern int mlt_properties_inc_ref( mlt_properties self ); extern int mlt_properties_dec_ref( mlt_properties self ); extern int mlt_properties_ref_count( mlt_properties self ); diff --git a/src/framework/mlt_repository.c b/src/framework/mlt_repository.c index 3d75bcbe..81b80654 100644 --- a/src/framework/mlt_repository.c +++ b/src/framework/mlt_repository.c @@ -26,11 +26,14 @@ #include "mlt_properties.h" #include "mlt_tokeniser.h" #include "mlt_log.h" +#include "mlt_factory.h" #include #include #include #include +#include +#include /** \brief Repository class * @@ -426,3 +429,71 @@ mlt_properties mlt_repository_languages( mlt_repository self ) mlt_properties_set_data( &self->parent, "languages", languages, 0, ( mlt_destructor )mlt_properties_close, NULL ); return languages; } + +static void list_presets( mlt_properties properties, const char *path, const char *dirname ) +{ + DIR *dir = opendir( dirname ); + + if ( dir ) + { + struct dirent *de = readdir( dir ); + char fullname[ PATH_MAX ]; + + while ( de != NULL ) + { + if ( de->d_name[0] != '.' && de->d_name[strlen( de->d_name ) - 1] != '~' ) + { + snprintf( fullname, sizeof(fullname), "%s/%s", dirname, de->d_name ); + if ( de->d_type & DT_DIR ) + { + // recurse into subdirectories + char sub[ PATH_MAX ]; + if ( path ) + snprintf( sub, sizeof(sub), "%s/%s", path, de->d_name ); + else + strncpy( sub, de->d_name, sizeof(sub) ); + list_presets( properties, sub, fullname ); + } + else + { + // load the preset + mlt_properties preset = mlt_properties_load( fullname ); + if ( preset && mlt_properties_count( preset ) ) + { + snprintf( fullname, 1024, "%s/%s", path, de->d_name ); + mlt_properties_set_data( properties, fullname, preset, 0, (mlt_destructor) mlt_properties_close, NULL ); + } + } + } + de = readdir( dir ); + } + closedir( dir ); + } +} + +/** Get the list of presets. + * + * \public \memberof mlt_repository_s + * \return a properties list of all the presets + */ + +mlt_properties mlt_repository_presets( ) +{ + mlt_properties result = mlt_properties_new(); + char *path = getenv( "MLT_PRESETS_PATH" ); + + if ( path ) + { + path = strdup( path ); + } + else + { + path = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + 9 ); + strcpy( path, mlt_environment( "MLT_DATA" ) ); + strcat( path, "/presets" ); + } + list_presets( result, NULL, path ); + free( path ); + + return result; +} diff --git a/src/framework/mlt_repository.h b/src/framework/mlt_repository.h index a653b490..29fb3373 100644 --- a/src/framework/mlt_repository.h +++ b/src/framework/mlt_repository.h @@ -66,6 +66,7 @@ extern mlt_properties mlt_repository_transitions( mlt_repository self ); extern void mlt_repository_register_metadata( mlt_repository self, mlt_service_type type, const char *service, mlt_metadata_callback, void *callback_data ); extern mlt_properties mlt_repository_metadata( mlt_repository self, mlt_service_type type, const char *service ); extern mlt_properties mlt_repository_languages( mlt_repository self ); +extern mlt_properties mlt_repository_presets( ); #endif diff --git a/src/melt/melt.c b/src/melt/melt.c index d5967240..6028a439 100644 --- a/src/melt/melt.c +++ b/src/melt/melt.c @@ -325,6 +325,7 @@ static void show_usage( char *program_name ) " -query \"producers\" | \"producer\"=id List producers or show info about one\n" " -query \"transitions\" | \"transition\"=id List transitions, show info about one\n" " -query \"profiles\" | \"profile\"=id List profiles, show info about one\n" +" -query \"presets\" | \"preset\"=id List presets, show info about one\n" " -query \"formats\" List audio/video formats\n" " -query \"audio_codecs\" List audio codecs\n" " -query \"video_codecs\" List video codecs\n" @@ -468,6 +469,37 @@ static void query_profile( const char *id ) mlt_properties_close( profiles ); } +static void query_presets() +{ + mlt_properties presets = mlt_repository_presets(); + fprintf( stderr, "---\npresets:\n" ); + if ( presets ) + { + int j; + for ( j = 0; j < mlt_properties_count( presets ); j++ ) + fprintf( stderr, " - %s\n", mlt_properties_get_name( presets, j ) ); + } + fprintf( stderr, "...\n" ); + mlt_properties_close( presets ); +} + +static void query_preset( const char *id ) +{ + mlt_properties presets = mlt_repository_presets(); + mlt_properties preset = mlt_properties_get_data( presets, id, NULL ); + if ( preset ) + { + char *s = mlt_properties_serialise_yaml( preset ); + fprintf( stderr, "%s", s ); + free( s ); + } + else + { + fprintf( stderr, "# No metadata for preset \"%s\"\n", id ); + } + mlt_properties_close( presets ); +} + static void query_formats( ) { mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); @@ -580,6 +612,8 @@ int main( int argc, char **argv ) query_services( repo, transition_type ); else if ( !strcmp( pname, "profiles" ) || !strcmp( pname, "profile" ) ) query_profiles(); + else if ( !strcmp( pname, "presets" ) || !strcmp( pname, "preset" ) ) + query_presets(); else if ( !strncmp( pname, "format", 6 ) ) query_formats(); else if ( !strncmp( pname, "acodec", 6 ) || !strcmp( pname, "audio_codecs" ) ) @@ -597,6 +631,8 @@ int main( int argc, char **argv ) query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "profile=", 8 ) ) query_profile( strchr( pname, '=' ) + 1 ); + else if ( !strncmp( pname, "preset=", 7 ) ) + query_preset( strchr( pname, '=' ) + 1 ); else goto query_all; } diff --git a/src/mlt++/MltProperties.cpp b/src/mlt++/MltProperties.cpp index 8317294c..b2ae778c 100644 --- a/src/mlt++/MltProperties.cpp +++ b/src/mlt++/MltProperties.cpp @@ -316,3 +316,9 @@ char *Properties::serialise_yaml( ) { return mlt_properties_serialise_yaml( get_properties( ) ); } + +int Properties::preset( const char *name ) +{ + return mlt_properties_preset( get_properties(), name ); +} + diff --git a/src/mlt++/MltProperties.h b/src/mlt++/MltProperties.h index fce173ff..8956a56c 100644 --- a/src/mlt++/MltProperties.h +++ b/src/mlt++/MltProperties.h @@ -93,6 +93,7 @@ namespace Mlt bool is_sequence( ); static Properties *parse_yaml( const char *file ); char *serialise_yaml( ); + int preset( const char *name ); }; } diff --git a/src/mlt++/MltRepository.cpp b/src/mlt++/MltRepository.cpp index 38760796..00e4b4c6 100644 --- a/src/mlt++/MltRepository.cpp +++ b/src/mlt++/MltRepository.cpp @@ -84,3 +84,8 @@ Properties *Repository::languages( ) const { return new Properties( mlt_repository_languages( instance ) ); } + +Properties *Repository::presets( ) +{ + return new Properties( mlt_repository_presets( ) ); +} diff --git a/src/mlt++/MltRepository.h b/src/mlt++/MltRepository.h index efce9f29..53e529e6 100644 --- a/src/mlt++/MltRepository.h +++ b/src/mlt++/MltRepository.h @@ -52,6 +52,7 @@ namespace Mlt void register_metadata( mlt_service_type type, const char *service, mlt_metadata_callback, void *callback_data ); Properties *metadata( mlt_service_type type, const char *service ) const; Properties *languages( ) const; + static Properties *presets(); }; } diff --git a/src/swig/mlt.i b/src/swig/mlt.i index f453f1e0..20434e44 100644 --- a/src/swig/mlt.i +++ b/src/swig/mlt.i @@ -61,6 +61,7 @@ namespace Mlt { %newobject Repository::metadata( mlt_service_type, const char * ); %newobject Repository::languages( ); %newobject Profile::list(); +%newobject Repository::presets(); } /** Classes to wrap.