3 * \brief the factory method interfaces
5 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
6 * \author Charles Yates <charles.yates@pandora.be>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "mlt_repository.h"
34 /** the default subdirectory of the libdir for holding modules (plugins) */
35 #define PREFIX_LIB "\\lib\\mlt"
36 /** the default subdirectory of the install prefix for holding module (plugin) data */
37 #define PREFIX_DATA "\\share\\mlt"
38 #elif defined(__DARWIN__) && defined(RELOCATABLE)
39 #include <mach-o/dyld.h>
40 /** the default subdirectory of the libdir for holding modules (plugins) */
41 #define PREFIX_LIB "/lib/mlt"
42 /** the default subdirectory of the install prefix for holding module (plugin) data */
43 #define PREFIX_DATA "/share/mlt"
45 /** the default subdirectory of the libdir for holding modules (plugins) */
46 #define PREFIX_LIB LIBDIR "/mlt"
47 /** the default subdirectory of the install prefix for holding module (plugin) data */
48 #define PREFIX_DATA MLTDATADIR "/mlt"
51 /** holds the full path to the modules directory - initialized and retained for the entire session */
52 static char *mlt_directory = NULL;
53 /** a global properties list for holding environment config data and things needing session-oriented cleanup */
54 static mlt_properties global_properties = NULL;
55 /** the global repository singleton */
56 static mlt_repository repository = NULL;
57 /** the events object for the factory events */
58 static mlt_properties event_object = NULL;
59 /** for tracking the unique_id set on each constructed service */
60 static int unique_id = 0;
62 /* Event transmitters. */
64 /** the -create-request event transmitter
72 static void mlt_factory_create_request( mlt_listener listener, mlt_properties owner, mlt_service self, void **args )
74 if ( listener != NULL )
75 listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service * )args[ 2 ] );
78 /** the -create-done event transmitter
86 static void mlt_factory_create_done( mlt_listener listener, mlt_properties owner, mlt_service self, void **args )
88 if ( listener != NULL )
89 listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] );
92 /** Construct the repository and factories.
94 * The environment variable MLT_PRODUCER is the name of a default producer often used by other services, defaults to "loader".
96 * The environment variable MLT_CONSUMER is the name of a default consumer, defaults to "sdl".
98 * The environment variable MLT_TEST_CARD is the name of a producer or file to be played when nothing is available (all tracks blank).
100 * The environment variable MLT_DATA overrides the default full path to the MLT and module supplemental data files, defaults to \p PREFIX_DATA.
102 * The environment variable MLT_PROFILE defaults to "dv_pal."
104 * The environment variable MLT_REPOSITORY overrides the default location of the plugin modules, defaults to \p PREFIX_LIB.
106 * \param directory an optional full path to a directory containing the modules that overrides the default and
107 * the MLT_REPOSITORY environment variable
108 * \return the repository
111 mlt_repository mlt_factory_init( const char *directory )
113 // Load the system locales
114 setlocale( LC_ALL, "" );
116 if ( ! global_properties )
117 global_properties = mlt_properties_new( );
119 // Allow property refresh on a subsequent initialisation
120 if ( global_properties )
122 mlt_properties_set_or_default( global_properties, "MLT_NORMALISATION", getenv( "MLT_NORMALISATION" ), "PAL" );
123 mlt_properties_set_or_default( global_properties, "MLT_PRODUCER", getenv( "MLT_PRODUCER" ), "loader" );
124 mlt_properties_set_or_default( global_properties, "MLT_CONSUMER", getenv( "MLT_CONSUMER" ), "sdl" );
125 mlt_properties_set( global_properties, "MLT_TEST_CARD", getenv( "MLT_TEST_CARD" ) );
126 mlt_properties_set_or_default( global_properties, "MLT_PROFILE", getenv( "MLT_PROFILE" ), "dv_pal" );
127 mlt_properties_set_or_default( global_properties, "MLT_DATA", getenv( "MLT_DATA" ), PREFIX_DATA );
130 DWORD size = sizeof( path );
131 GetModuleFileName( NULL, path, size );
132 #elif defined(__DARWIN__) && defined(RELOCATABLE)
134 uint32_t size = sizeof( path );
135 _NSGetExecutablePath( path, &size );
137 #if defined(WIN32) || (defined(__DARWIN__) && defined(RELOCATABLE))
138 char *path2 = strdup( path );
139 char *appdir = dirname( path2 );
140 mlt_properties_set( global_properties, "MLT_APPDIR", appdir );
145 // Only initialise once
146 if ( mlt_directory == NULL )
148 // Allow user over rides
149 if ( directory == NULL || !strcmp( directory, "" ) )
150 directory = getenv( "MLT_REPOSITORY" );
152 // If no directory is specified, default to install directory
153 if ( directory == NULL )
154 directory = PREFIX_LIB;
156 // Store the prefix for later retrieval
157 #if defined(WIN32) || (defined(__DARWIN__) && defined(RELOCATABLE))
158 char *exedir = mlt_environment( "MLT_APPDIR" );
159 size_t size = strlen( exedir );
160 if ( global_properties && !getenv( "MLT_DATA" ) )
162 mlt_directory = calloc( 1, size + strlen( PREFIX_DATA ) + 1 );
163 strcpy( mlt_directory, exedir );
164 strcat( mlt_directory, PREFIX_DATA );
165 mlt_properties_set( global_properties, "MLT_DATA", mlt_directory );
166 free( mlt_directory );
168 mlt_directory = calloc( 1, size + strlen( directory ) + 1 );
169 strcpy( mlt_directory, exedir );
170 strcat( mlt_directory, directory );
172 mlt_directory = strdup( directory );
175 // Initialise the pool
178 // Create and set up the events object
179 event_object = mlt_properties_new( );
180 mlt_events_init( event_object );
181 mlt_events_register( event_object, "producer-create-request", ( mlt_transmitter )mlt_factory_create_request );
182 mlt_events_register( event_object, "producer-create-done", ( mlt_transmitter )mlt_factory_create_done );
183 mlt_events_register( event_object, "filter-create-request", ( mlt_transmitter )mlt_factory_create_request );
184 mlt_events_register( event_object, "filter-create-done", ( mlt_transmitter )mlt_factory_create_done );
185 mlt_events_register( event_object, "transition-create-request", ( mlt_transmitter )mlt_factory_create_request );
186 mlt_events_register( event_object, "transition-create-done", ( mlt_transmitter )mlt_factory_create_done );
187 mlt_events_register( event_object, "consumer-create-request", ( mlt_transmitter )mlt_factory_create_request );
188 mlt_events_register( event_object, "consumer-create-done", ( mlt_transmitter )mlt_factory_create_done );
190 // Create the repository of services
191 repository = mlt_repository_init( mlt_directory );
193 // Force a clean up when app closes
194 atexit( mlt_factory_close );
200 /** Fetch the events object.
202 * \return the global factory event object
205 mlt_properties mlt_factory_event_object( )
210 /** Fetch the module directory used in this instance.
212 * \return the full path to the module directory that this session is using
215 const char *mlt_factory_directory( )
217 return mlt_directory;
220 /** Get a value from the environment.
222 * \param name the name of a MLT (runtime configuration) environment variable
223 * \return the value of the variable
226 char *mlt_environment( const char *name )
228 if ( global_properties )
229 return mlt_properties_get( global_properties, name );
234 /** Set a value in the environment.
236 * \param name the name of a MLT environment variable
237 * \param value the value of the variable
238 * \return true on error
241 int mlt_environment_set( const char *name, const char *value )
243 if ( global_properties )
244 return mlt_properties_set( global_properties, name, value );
249 /** Set some properties common to all services.
251 * This sets _unique_id, \p mlt_type, \p mlt_service (unless _mlt_service_hidden), and _profile.
253 * \param properties a service's properties list
254 * \param profile the \p mlt_profile supplied to the factory function
255 * \param type the MLT service class
256 * \param service the name of the service
259 static void set_common_properties( mlt_properties properties, mlt_profile profile, const char *type, const char *service )
261 mlt_properties_set_int( properties, "_unique_id", ++ unique_id );
262 mlt_properties_set( properties, "mlt_type", type );
263 if ( mlt_properties_get_int( properties, "_mlt_service_hidden" ) == 0 )
264 mlt_properties_set( properties, "mlt_service", service );
265 if ( profile != NULL )
266 mlt_properties_set_data( properties, "_profile", profile, 0, NULL, NULL );
269 /** Fetch a producer from the repository.
271 * \param profile the \p mlt_profile to use
272 * \param service the name of the producer (optional, defaults to MLT_PRODUCER)
273 * \param input an optional argument to the producer constructor, typically a string
274 * \return a new producer
277 mlt_producer mlt_factory_producer( mlt_profile profile, const char *service, const void *input )
279 mlt_producer obj = NULL;
281 // Pick up the default normalising producer if necessary
282 if ( service == NULL )
283 service = mlt_environment( "MLT_PRODUCER" );
285 // Offer the application the chance to 'create'
286 mlt_events_fire( event_object, "producer-create-request", service, input, &obj, NULL );
288 // Try to instantiate via the specified service
291 obj = mlt_repository_create( repository, profile, producer_type, service, input );
292 mlt_events_fire( event_object, "producer-create-done", service, input, obj, NULL );
295 mlt_properties properties = MLT_PRODUCER_PROPERTIES( obj );
296 set_common_properties( properties, profile, "producer", service );
302 /** Fetch a filter from the repository.
304 * \param profile the \p mlt_profile to use
305 * \param service the name of the filter
306 * \param input an optional argument to the filter constructor, typically a string
307 * \return a new filter
310 mlt_filter mlt_factory_filter( mlt_profile profile, const char *service, const void *input )
312 mlt_filter obj = NULL;
314 // Offer the application the chance to 'create'
315 mlt_events_fire( event_object, "filter-create-request", service, input, &obj, NULL );
319 obj = mlt_repository_create( repository, profile, filter_type, service, input );
320 mlt_events_fire( event_object, "filter-create-done", service, input, obj, NULL );
325 mlt_properties properties = MLT_FILTER_PROPERTIES( obj );
326 set_common_properties( properties, profile, "filter", service );
331 /** Fetch a transition from the repository.
333 * \param profile the \p mlt_profile to use
334 * \param service the name of the transition
335 * \param input an optional argument to the transition constructor, typically a string
336 * \return a new transition
339 mlt_transition mlt_factory_transition( mlt_profile profile, const char *service, const void *input )
341 mlt_transition obj = NULL;
343 // Offer the application the chance to 'create'
344 mlt_events_fire( event_object, "transition-create-request", service, input, &obj, NULL );
348 obj = mlt_repository_create( repository, profile, transition_type, service, input );
349 mlt_events_fire( event_object, "transition-create-done", service, input, obj, NULL );
354 mlt_properties properties = MLT_TRANSITION_PROPERTIES( obj );
355 set_common_properties( properties, profile, "transition", service );
360 /** Fetch a consumer from the repository.
362 * \param profile the \p mlt_profile to use
363 * \param service the name of the consumer (optional, defaults to MLT_CONSUMER)
364 * \param input an optional argument to the consumer constructor, typically a string
365 * \return a new consumer
368 mlt_consumer mlt_factory_consumer( mlt_profile profile, const char *service, const void *input )
370 mlt_consumer obj = NULL;
372 if ( service == NULL )
373 service = mlt_environment( "MLT_CONSUMER" );
375 // Offer the application the chance to 'create'
376 mlt_events_fire( event_object, "consumer-create-request", service, input, &obj, NULL );
380 obj = mlt_repository_create( repository, profile, consumer_type, service, input );
381 mlt_events_fire( event_object, "consumer-create-done", service, input, obj, NULL );
386 mlt_properties properties = MLT_CONSUMER_PROPERTIES( obj );
387 set_common_properties( properties, profile, "consumer", service );
392 /** Register an object for clean up.
394 * \param ptr an opaque pointer to anything allocated on the heap
395 * \param destructor the function pointer of the deallocation subroutine (e.g., free or \p mlt_pool_release)
398 void mlt_factory_register_for_clean_up( void *ptr, mlt_destructor destructor )
401 sprintf( unique, "%08d", mlt_properties_count( global_properties ) );
402 mlt_properties_set_data( global_properties, unique, ptr, 0, destructor, NULL );
405 /** Close the factory.
407 * Cleanup all resources for the session.
410 void mlt_factory_close( )
412 if ( mlt_directory != NULL )
414 mlt_properties_close( event_object );
416 mlt_properties_close( global_properties );
417 global_properties = NULL;
420 mlt_repository_close( repository );
423 free( mlt_directory );
424 mlt_directory = NULL;
429 mlt_properties mlt_global_properties( )
431 return global_properties;