]> git.sesse.net Git - mlt/blob - src/melt/melt.c
Presets!
[mlt] / src / melt / melt.c
1 /*
2  * melt.c -- MLT command line utility
3  * Copyright (C) 2002-2011 Ushodaya Enterprises Limited
4  * Authors: Charles Yates <charles.yates@pandora.be>
5  *          Dan Dennedy <dan@dennedy.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #ifndef _GNU_SOURCE
23 #define _GNU_SOURCE
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sched.h>
29 #include <libgen.h>
30 #include <limits.h>
31
32 #include <framework/mlt.h>
33
34 #if defined(__DARWIN__) || defined(WIN32)
35 #include <SDL.h>
36 #endif
37
38 #include "io.h"
39
40 static void transport_action( mlt_producer producer, char *value )
41 {
42         mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
43         mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL );
44         mlt_consumer consumer = mlt_properties_get_data( properties, "transport_consumer", NULL );
45
46         mlt_properties_set_int( properties, "stats_off", 1 );
47
48         if ( strlen( value ) == 1 )
49         {
50                 switch( value[ 0 ] )
51                 {
52                         case 'q':
53                         case 'Q':
54                                 mlt_properties_set_int( properties, "done", 1 );
55                                 break;
56                         case '0':
57                                 mlt_producer_set_speed( producer, 1 );
58                                 mlt_producer_seek( producer, 0 );
59                                 break;
60                         case '1':
61                                 mlt_producer_set_speed( producer, -10 );
62                                 break;
63                         case '2':
64                                 mlt_producer_set_speed( producer, -5 );
65                                 break;
66                         case '3':
67                                 mlt_producer_set_speed( producer, -2 );
68                                 break;
69                         case '4':
70                                 mlt_producer_set_speed( producer, -1 );
71                                 break;
72                         case '5':
73                                 mlt_producer_set_speed( producer, 0 );
74                                 break;
75                         case '6':
76                         case ' ':
77                                 mlt_producer_set_speed( producer, 1 );
78                                 break;
79                         case '7':
80                                 mlt_producer_set_speed( producer, 2 );
81                                 break;
82                         case '8':
83                                 mlt_producer_set_speed( producer, 5 );
84                                 break;
85                         case '9':
86                                 mlt_producer_set_speed( producer, 10 );
87                                 break;
88                         case 'd':
89                                 if ( multitrack != NULL )
90                                 {
91                                         int i = 0;
92                                         mlt_position last = -1;
93                                         fprintf( stderr, "\n" );
94                                         for ( i = 0; 1; i ++ )
95                                         {
96                                                 mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i );
97                                                 if ( time == last )
98                                                         break;
99                                                 last = time;
100                                                 fprintf( stderr, "%d: %d\n", i, (int)time );
101                                         }
102                                 }
103                                 break;
104
105                         case 'g':
106                                 if ( multitrack != NULL )
107                                 {
108                                         mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 );
109                                         mlt_producer_seek( producer, time );
110                                 }
111                                 break;
112                         case 'H':
113                                 if ( producer != NULL )
114                                 {
115                                         mlt_position position = mlt_producer_position( producer );
116                                         mlt_producer_seek( producer, position - ( mlt_producer_get_fps( producer ) * 60 ) );
117                                 }
118                                 break;
119                         case 'h':
120                                 if ( producer != NULL )
121                                 {
122                                         mlt_position position = mlt_producer_position( producer );
123                                         mlt_producer_set_speed( producer, 0 );
124                                         mlt_producer_seek( producer, position - 1 );
125                                 }
126                                 break;
127                         case 'j':
128                                 if ( multitrack != NULL )
129                                 {
130                                         mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 );
131                                         mlt_producer_seek( producer, time );
132                                 }
133                                 break;
134                         case 'k':
135                                 if ( multitrack != NULL )
136                                 {
137                                         mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 );
138                                         mlt_producer_seek( producer, time );
139                                 }
140                                 break;
141                         case 'l':
142                                 if ( producer != NULL )
143                                 {
144                                         mlt_position position = mlt_producer_position( producer );
145                                         if ( mlt_producer_get_speed( producer ) != 0 )
146                                                 mlt_producer_set_speed( producer, 0 );
147                                         else
148                                                 mlt_producer_seek( producer, position + 1 );
149                                 }
150                                 break;
151                         case 'L':
152                                 if ( producer != NULL )
153                                 {
154                                         mlt_position position = mlt_producer_position( producer );
155                                         mlt_producer_seek( producer, position + ( mlt_producer_get_fps( producer ) * 60 ) );
156                                 }
157                                 break;
158                 }
159
160                 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 );
161         }
162
163         mlt_properties_set_int( properties, "stats_off", 0 );
164 }
165
166 static mlt_consumer create_consumer( mlt_profile profile, char *id )
167 {
168         char *myid = id ? strdup( id ) : NULL;
169         char *arg = myid ? strchr( myid, ':' ) : NULL;
170         if ( arg != NULL )
171                 *arg ++ = '\0';
172         mlt_consumer consumer = mlt_factory_consumer( profile, myid, arg );
173         if ( consumer != NULL )
174         {
175                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
176                 mlt_properties_set_data( properties, "transport_callback", transport_action, 0, NULL, NULL );
177         }
178         if ( myid )
179                 free( myid );
180         return consumer;
181 }
182
183 static void load_consumer( mlt_consumer *consumer, mlt_profile profile, int argc, char **argv )
184 {
185         int i;
186         for ( i = 1; i < argc; i ++ )
187         {
188                 if ( !strcmp( argv[ i ], "-consumer" ) )
189                 {
190                         if ( *consumer )
191                                 mlt_consumer_close( *consumer );
192                         *consumer = create_consumer( profile, argv[ ++ i ] );
193                         if ( *consumer )
194                         {
195                                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( *consumer );
196                                 while ( argv[ i + 1 ] != NULL && strstr( argv[ i + 1 ], "=" ) )
197                                         mlt_properties_parse( properties, argv[ ++ i ] );
198                         }
199                 }
200         }
201 }
202
203 #if defined(__DARWIN__) || defined(WIN32)
204
205 static void event_handling( mlt_producer producer, mlt_consumer consumer )
206 {
207         SDL_Event event;
208
209         while ( SDL_PollEvent( &event ) )
210         {
211                 switch( event.type )
212                 {
213                         case SDL_QUIT:
214                                 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( consumer ), "done", 1 );
215                                 break;
216
217                         case SDL_KEYDOWN:
218                                 if ( event.key.keysym.unicode < 0x80 && event.key.keysym.unicode > 0 )
219                                 {
220                                         char keyboard[ 2 ] = { event.key.keysym.unicode, 0 };
221                                         transport_action( producer, keyboard );
222                                 }
223                                 break;
224                 }
225         }
226 }
227
228 #endif
229
230 static void transport( mlt_producer producer, mlt_consumer consumer )
231 {
232         mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
233         int silent = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent" );
234         int progress = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress" );
235         struct timespec tm = { 0, 40000 };
236         int total_length = mlt_producer_get_length( producer );
237         int last_position = 0;
238
239         if ( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) )
240         {
241                 if ( !silent && !progress )
242                 {
243                         term_init( );
244
245                         fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" );
246                         fprintf( stderr, "|1=-10| |2= -5| |3= -2| |4= -1| |5=  0| |6=  1| |7=  2| |8=  5| |9= 10|\n" );
247                         fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" );
248
249                         fprintf( stderr, "+---------------------------------------------------------------------+\n" );
250                         fprintf( stderr, "|               H = back 1 minute,  L = forward 1 minute              |\n" );
251                         fprintf( stderr, "|                 h = previous frame,  l = next frame                 |\n" );
252                         fprintf( stderr, "|           g = start of clip, j = next clip, k = previous clip       |\n" );
253                         fprintf( stderr, "|                0 = restart, q = quit, space = play                  |\n" );
254                         fprintf( stderr, "+---------------------------------------------------------------------+\n" );
255                 }
256
257                 while( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) )
258                 {
259                         int value = ( silent || progress )? -1 : term_read( );
260
261                         if ( value != -1 )
262                         {
263                                 char string[ 2 ] = { value, 0 };
264                                 transport_action( producer, string );
265                         }
266
267 #if defined(__DARWIN__) || defined(WIN32)
268                         event_handling( producer, consumer );
269 #endif
270
271                         if ( !silent && mlt_properties_get_int( properties, "stats_off" ) == 0 )
272                         {
273                                 if ( progress )
274                                 {
275                                         int current_position = mlt_producer_position( producer );
276                                         if ( current_position > last_position )
277                                         {
278                                                 fprintf( stderr, "Current Frame: %10d, percentage: %10d\r",
279                                                         current_position, 100 * current_position / total_length );
280                                                 last_position = current_position;
281                                         }
282                                 }
283                                 else
284                                 {
285                                         fprintf( stderr, "Current Position: %10d\r", (int)mlt_consumer_position( consumer ) );
286                                 }
287                         }
288
289                         if ( silent || progress )
290                                 nanosleep( &tm, NULL );
291                 }
292
293                 if ( !silent )
294                         fprintf( stderr, "\n" );
295         }
296 }
297
298 static void show_usage( char *program_name )
299 {
300         fprintf( stderr,
301 "Usage: %s [options] [producer [name=value]* ]+\n"
302 "Options:\n"
303 "  -attach filter[:arg] [name=value]*       Attach a filter to the output\n"
304 "  -attach-cut filter[:arg] [name=value]*   Attach a filter to a cut\n"
305 "  -attach-track filter[:arg] [name=value]* Attach a filter to a track\n"
306 "  -attach-clip filter[:arg] [name=value]*  Attach a filter to a producer\n"
307 "  -audio-track | -hide-video               Add an audio-only track\n"
308 "  -blank frames                            Add blank silence to a track\n"
309 "  -consumer id[:arg] [name=value]*         Set the consumer (sink)\n"
310 "  -debug                                   Set the logging level to debug\n"
311 "  -filter filter[:arg] [name=value]*       Add a filter to the current track\n"
312 "  -group [name=value]*                     Apply properties repeatedly\n"
313 "  -help                                    Show this message\n"
314 "  -join clips                              Join multiple clips into one cut\n"
315 "  -mix length                              Add a mix between the last two cuts\n"
316 "  -mixer transition                        Add a transition to the mix\n"
317 "  -null-track | -hide-track                Add a hidden track\n"
318 "  -profile name                            Set the processing settings\n"
319 "  -progress                                Display progress along with position\n"
320 "  -remove                                  Remove the most recent cut\n"
321 "  -repeat times                            Repeat the last cut\n"
322 "  -query                                   List all of the registered services\n"
323 "  -query \"consumers\" | \"consumer\"=id       List consumers or show info about one\n"
324 "  -query \"filters\" | \"filter\"=id           List filters or show info about one\n"
325 "  -query \"producers\" | \"producer\"=id       List producers or show info about one\n"
326 "  -query \"transitions\" | \"transition\"=id   List transitions, show info about one\n"
327 "  -query \"profiles\" | \"profile\"=id         List profiles, show info about one\n"
328 "  -query \"presets\" | \"preset\"=id           List presets, show info about one\n"
329 "  -query \"formats\"                         List audio/video formats\n"
330 "  -query \"audio_codecs\"                    List audio codecs\n"
331 "  -query \"video_codecs\"                    List video codecs\n"
332 "  -serialise [filename]                    Write the commands to a text file\n"
333 "  -silent                                  Do not display position/transport\n"
334 "  -split relative-frame                    Split the last cut into two cuts\n"
335 "  -swap                                    Rearrange the last two cuts\n"
336 "  -track                                   Add a track\n"
337 "  -transition id[:arg] [name=value]*       Add a transition\n"
338 "  -verbose                                 Set the logging level to verbose\n"
339 "  -version                                 Show the version and copyright\n"
340 "  -video-track | -hide-audio               Add a video-only track\n"
341 "For more help: <http://www.mltframework.org/>\n",
342         basename( program_name ) );
343 }
344
345 static void guess_profile( mlt_producer melt, mlt_profile profile )
346 {
347         mlt_frame fr = NULL;
348         uint8_t *buffer;
349         mlt_image_format fmt = mlt_image_yuv422;
350         mlt_properties p;
351         int w = profile->width;
352         int h = profile->height;
353
354         if ( ! mlt_service_get_frame( MLT_PRODUCER_SERVICE(melt), &fr, 0 ) && fr )
355         {
356                 mlt_properties_set_double( MLT_FRAME_PROPERTIES( fr ), "consumer_aspect_ratio", mlt_profile_sar( profile ) );
357                 if ( ! mlt_frame_get_image( fr, &buffer, &fmt, &w, &h, 0 ) )
358                 {
359                         // Some source properties are not exposed until after the first get_image call.
360                         mlt_frame_close( fr );
361                         mlt_service_get_frame( MLT_PRODUCER_SERVICE(melt), &fr, 0 );
362                         p = MLT_FRAME_PROPERTIES( fr );
363 //                      mlt_properties_dump(p, stderr);
364                         if ( mlt_properties_get_int( p, "meta.media.frame_rate_den" ) && mlt_properties_get_int( p, "meta.media.sample_aspect_den" ) )
365                         {
366                                 profile->width = mlt_properties_get_int( p, "meta.media.width" );
367                                 profile->height = mlt_properties_get_int( p, "meta.media.height" );
368                                 profile->progressive = mlt_properties_get_int( p, "meta.media.progressive" );
369                                 profile->frame_rate_num = mlt_properties_get_int( p, "meta.media.frame_rate_num" );
370                                 profile->frame_rate_den = mlt_properties_get_int( p, "meta.media.frame_rate_den" );
371                                 // AVCHD is mis-reported as double frame rate.
372                                 if ( profile->progressive == 0 && (
373                                      profile->frame_rate_num / profile->frame_rate_den == 50 ||
374                                      profile->frame_rate_num / profile->frame_rate_den == 59 ) )
375                                         profile->frame_rate_num /= 2;
376                                 profile->sample_aspect_num = mlt_properties_get_int( p, "meta.media.sample_aspect_num" );
377                                 profile->sample_aspect_den = mlt_properties_get_int( p, "meta.media.sample_aspect_den" );
378                                 profile->colorspace = mlt_properties_get_int( p, "meta.media.colorspace" );
379                                 profile->display_aspect_num = (int) ( (double) profile->sample_aspect_num * profile->width / profile->sample_aspect_den + 0.5 );
380                                 profile->display_aspect_den = profile->height;
381                                 free( profile->description );
382                                 profile->description = strdup( "automatic" );
383                                 profile->is_explicit = 0;
384                         }
385                 }
386         }
387         mlt_frame_close( fr );
388         mlt_producer_seek( melt, 0 );
389 }
390
391 static void query_metadata( mlt_repository repo, mlt_service_type type, const char *typestr, char *id )
392 {
393         mlt_properties metadata = mlt_repository_metadata( repo, type, id );
394         if ( metadata )
395         {
396                 char *s = mlt_properties_serialise_yaml( metadata );
397                 fprintf( stderr, "%s", s );
398                 free( s );
399         }
400         else
401         {
402                 fprintf( stderr, "# No metadata for %s \"%s\"\n", typestr, id );
403         }
404 }
405
406 static void query_services( mlt_repository repo, mlt_service_type type )
407 {
408         mlt_properties services = NULL;
409         const char *typestr = NULL;
410         switch ( type )
411         {
412                 case consumer_type:
413                         services = mlt_repository_consumers( repo );
414                         typestr = "consumers";
415                         break;
416                 case filter_type:
417                         services = mlt_repository_filters( repo );
418                         typestr = "filters";
419                         break;
420                 case producer_type:
421                         services = mlt_repository_producers( repo );
422                         typestr = "producers";
423                         break;
424                 case transition_type:
425                         services = mlt_repository_transitions( repo );
426                         typestr = "transitions";
427                         break;
428                 default:
429                         return;
430         }
431         fprintf( stderr, "---\n%s:\n", typestr );
432         if ( services )
433         {
434                 int j;
435                 for ( j = 0; j < mlt_properties_count( services ); j++ )
436                         fprintf( stderr, "  - %s\n", mlt_properties_get_name( services, j ) );
437         }
438         fprintf( stderr, "...\n" );
439 }
440
441 static void query_profiles()
442 {
443         mlt_properties profiles = mlt_profile_list();
444         fprintf( stderr, "---\nprofiles:\n" );
445         if ( profiles )
446         {
447                 int j;
448                 for ( j = 0; j < mlt_properties_count( profiles ); j++ )
449                         fprintf( stderr, "  - %s\n", mlt_properties_get_name( profiles, j ) );
450         }
451         fprintf( stderr, "...\n" );
452         mlt_properties_close( profiles );
453 }
454
455 static void query_profile( const char *id )
456 {
457         mlt_properties profiles = mlt_profile_list();
458         mlt_properties profile = mlt_properties_get_data( profiles, id, NULL );
459         if ( profile )
460         {
461                 char *s = mlt_properties_serialise_yaml( profile );
462                 fprintf( stderr, "%s", s );
463                 free( s );
464         }
465         else
466         {
467                 fprintf( stderr, "# No metadata for profile \"%s\"\n", id );
468         }
469         mlt_properties_close( profiles );
470 }
471
472 static void query_presets()
473 {
474         mlt_properties presets = mlt_repository_presets();
475         fprintf( stderr, "---\npresets:\n" );
476         if ( presets )
477         {
478                 int j;
479                 for ( j = 0; j < mlt_properties_count( presets ); j++ )
480                         fprintf( stderr, "  - %s\n", mlt_properties_get_name( presets, j ) );
481         }
482         fprintf( stderr, "...\n" );
483         mlt_properties_close( presets );
484 }
485
486 static void query_preset( const char *id )
487 {
488         mlt_properties presets = mlt_repository_presets();
489         mlt_properties preset = mlt_properties_get_data( presets, id, NULL );
490         if ( preset )
491         {
492                 char *s = mlt_properties_serialise_yaml( preset );
493                 fprintf( stderr, "%s", s );
494                 free( s );
495         }
496         else
497         {
498                 fprintf( stderr, "# No metadata for preset \"%s\"\n", id );
499         }
500         mlt_properties_close( presets );
501 }
502
503 static void query_formats( )
504 {
505         mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL );
506         if ( consumer )
507         {
508                 mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "f", "list" );
509                 mlt_consumer_start( consumer );
510                 mlt_consumer_close( consumer );
511         }
512         else
513         {
514                 fprintf( stderr, "# No formats - failed to load avformat consumer\n" );
515         }
516 }
517
518 static void query_acodecs( )
519 {
520         mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL );
521         if ( consumer )
522         {
523                 mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "acodec", "list" );
524                 mlt_consumer_start( consumer );
525                 mlt_consumer_close( consumer );
526         }
527         else
528         {
529                 fprintf( stderr, "# No audio codecs - failed to load avformat consumer\n" );
530         }
531 }
532
533 static void query_vcodecs( )
534 {
535         mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL );
536         if ( consumer )
537         {
538                 mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "vcodec", "list" );
539                 mlt_consumer_start( consumer );
540                 mlt_consumer_close( consumer );
541         }
542         else
543         {
544                 fprintf( stderr, "# No video codecs - failed to load avformat consumer\n" );
545         }
546 }
547
548 static void on_fatal_error( mlt_properties owner, mlt_consumer consumer )
549 {
550         mlt_consumer_stop( consumer );
551         exit( EXIT_FAILURE );
552 }
553
554 int main( int argc, char **argv )
555 {
556         int i;
557         mlt_consumer consumer = NULL;
558         mlt_producer melt = NULL;
559         FILE *store = NULL;
560         char *name = NULL;
561         mlt_profile profile = NULL;
562         int is_progress = 0;
563         int is_silent = 0;
564         mlt_profile backup_profile;
565
566         // Construct the factory
567         mlt_repository repo = mlt_factory_init( NULL );
568
569 #ifdef WIN32
570         is_silent = 1;
571 #endif
572         
573         for ( i = 1; i < argc; i ++ )
574         {
575                 // Check for serialisation switch
576                 if ( !strcmp( argv[ i ], "-serialise" ) )
577                 {
578                         name = argv[ ++ i ];
579                         if ( name != NULL && strstr( name, ".melt" ) )
580                                 store = fopen( name, "w" );
581                         else
582                         {
583                                 if ( name == NULL || name[0] == '-' )
584                                         store = stdout;
585                                 name = NULL;
586                         }
587                 }
588                 // Look for the profile option
589                 else if ( !strcmp( argv[ i ], "-profile" ) )
590                 {
591                         const char *pname = argv[ ++ i ];
592                         if ( pname && pname[0] != '-' )
593                                 profile = mlt_profile_init( pname );
594                 }
595                 else if ( !strcmp( argv[ i ], "-progress" ) )
596                 {
597                         is_progress = 1;
598                 }
599                 // Look for the query option
600                 else if ( !strcmp( argv[ i ], "-query" ) )
601                 {
602                         const char *pname = argv[ ++ i ];
603                         if ( pname && pname[0] != '-' )
604                         {
605                                 if ( !strcmp( pname, "consumers" ) || !strcmp( pname, "consumer" ) )
606                                         query_services( repo, consumer_type );
607                                 else if ( !strcmp( pname, "filters" ) || !strcmp( pname, "filter" ) )
608                                         query_services( repo, filter_type );
609                                 else if ( !strcmp( pname, "producers" ) || !strcmp( pname, "producer" ) )
610                                         query_services( repo, producer_type );
611                                 else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) )
612                                         query_services( repo, transition_type );
613                                 else if ( !strcmp( pname, "profiles" ) || !strcmp( pname, "profile" ) )
614                                         query_profiles();
615                                 else if ( !strcmp( pname, "presets" ) || !strcmp( pname, "preset" ) )
616                                         query_presets();
617                                 else if ( !strncmp( pname, "format", 6 ) )
618                                         query_formats();
619                                 else if ( !strncmp( pname, "acodec", 6 ) || !strcmp( pname, "audio_codecs" ) )
620                                         query_acodecs();
621                                 else if ( !strncmp( pname, "vcodec", 6 ) || !strcmp( pname, "video_codecs" ) )
622                                         query_vcodecs();
623
624                                 else if ( !strncmp( pname, "consumer=", 9 ) )
625                                         query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 );
626                                 else if ( !strncmp( pname, "filter=", 7 ) )
627                                         query_metadata( repo, filter_type, "filter", strchr( pname, '=' ) + 1 );
628                                 else if ( !strncmp( pname, "producer=", 9 ) )
629                                         query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 );
630                                 else if ( !strncmp( pname, "transition=", 11 ) )
631                                         query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 );
632                                 else if ( !strncmp( pname, "profile=", 8 ) )
633                                         query_profile( strchr( pname, '=' ) + 1 );
634                                 else if ( !strncmp( pname, "preset=", 7 ) )
635                                         query_preset( strchr( pname, '=' ) + 1 );
636                                 else
637                                         goto query_all;
638                         }
639                         else
640                         {
641 query_all:
642                                 query_services( repo, consumer_type );
643                                 query_services( repo, filter_type );
644                                 query_services( repo, producer_type );
645                                 query_services( repo, transition_type );
646                                 fprintf( stderr, "# You can query the metadata for a specific service using:\n"
647                                         "# -query <type>=<identifer>\n"
648                                         "# where <type> is one of: consumer, filter, producer, or transition.\n" );
649                         }
650                         goto exit_factory;
651                 }
652                 else if ( !strcmp( argv[ i ], "-silent" ) )
653                 {
654                         is_silent = 1;
655                 }
656                 else if ( !strcmp( argv[ i ], "-verbose" ) )
657                 {
658                         mlt_log_set_level( MLT_LOG_VERBOSE );
659                 }
660                 else if ( !strcmp( argv[ i ], "-version" ) || !strcmp( argv[ i ], "--version" ) )
661                 {
662                         fprintf( stderr, "MLT %s " VERSION "\n"
663                                 "Copyright (C) 2002-2011 Ushodaya Enterprises Limited\n"
664                                 "<http://www.mltframework.org/>\n"
665                                 "This is free software; see the source for copying conditions.  There is NO\n"
666                                 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
667                                 basename( argv[0] ) );
668                         goto exit_factory;
669                 }
670                 else if ( !strcmp( argv[ i ], "-debug" ) )
671                 {
672                         mlt_log_set_level( MLT_LOG_DEBUG );
673                 }
674         }
675
676         // Create profile if not set explicitly
677         if ( getenv( "MLT_PROFILE" ) )
678                 profile = mlt_profile_init( NULL );
679         if ( profile == NULL )
680                 profile = mlt_profile_init( NULL );
681         else
682                 profile->is_explicit = 1;
683
684         // Look for the consumer option to load profile settings from consumer properties
685         backup_profile = mlt_profile_clone( profile );
686         load_consumer( &consumer, profile, argc, argv );
687
688         // If the consumer changed the profile, then it is explicit.
689         if ( backup_profile && !profile->is_explicit && (
690              profile->width != backup_profile->width ||
691              profile->height != backup_profile->height ||
692              profile->sample_aspect_num != backup_profile->sample_aspect_num ||
693              profile->sample_aspect_den != backup_profile->sample_aspect_den ||
694              profile->frame_rate_den != backup_profile->frame_rate_den ||
695              profile->frame_rate_num != backup_profile->frame_rate_num ||
696              profile->colorspace != backup_profile->colorspace ) )
697                 profile->is_explicit = 1;
698         mlt_profile_close( backup_profile );
699
700         // Get melt producer
701         if ( argc > 1 )
702                 melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] );
703
704         if ( melt )
705         {
706                 // Generate an automatic profile if needed.
707                 if ( ! profile->is_explicit )
708                 {
709                         guess_profile( melt, profile );
710                         mlt_producer_close( melt );
711                         melt = mlt_factory_producer( profile, "melt", &argv[ 1 ] );
712                 }
713                 
714                 // Reload the consumer with the fully qualified profile.
715                 // The producer or guess_profile could have changed the profile.
716                 load_consumer( &consumer, profile, argc, argv );
717
718                 // If we have no consumer, default to sdl
719                 if ( store == NULL && consumer == NULL )
720                         consumer = create_consumer( profile, NULL );
721         }
722         
723         // Set transport properties on consumer and produder
724         if ( consumer != NULL && melt != NULL )
725         {
726                 mlt_properties_set_data( MLT_CONSUMER_PROPERTIES( consumer ), "transport_producer", melt, 0, NULL, NULL );
727                 mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( melt ), "transport_consumer", consumer, 0, NULL, NULL );
728                 if ( is_progress )
729                         mlt_properties_set_int(  MLT_CONSUMER_PROPERTIES( consumer ), "progress", is_progress );
730                 if ( is_silent )
731                         mlt_properties_set_int(  MLT_CONSUMER_PROPERTIES( consumer ), "silent", is_silent );
732         }
733
734         if ( argc > 1 && melt != NULL && mlt_producer_get_length( melt ) > 0 )
735         {
736                 // Parse the arguments
737                 for ( i = 1; i < argc; i ++ )
738                 {
739                         if ( !strcmp( argv[ i ], "-serialise" ) )
740                         {
741                                 if ( store != stdout )
742                                         i ++;
743                         }
744                         else
745                         {
746                                 if ( store != NULL )
747                                         fprintf( store, "%s\n", argv[ i ] );
748
749                                 i ++;
750
751                                 while ( argv[ i ] != NULL && argv[ i ][ 0 ] != '-' )
752                                 {
753                                         if ( store != NULL )
754                                                 fprintf( store, "%s\n", argv[ i ] );
755                                         i += 1;
756                                 }
757
758                                 i --;
759                         }
760                 }
761
762                 if ( consumer != NULL && store == NULL )
763                 {
764                         // Get melt's properties
765                         mlt_properties melt_props = MLT_PRODUCER_PROPERTIES( melt );
766         
767                         // Get the last group
768                         mlt_properties group = mlt_properties_get_data( melt_props, "group", 0 );
769         
770                         // Apply group settings
771                         mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
772                         mlt_properties_inherit( properties, group );
773
774                         // Connect consumer to melt
775                         mlt_consumer_connect( consumer, MLT_PRODUCER_SERVICE( melt ) );
776
777                         // Start the consumer
778                         mlt_events_listen( properties, consumer, "consumer-fatal-error", ( mlt_listener )on_fatal_error );
779                         if ( mlt_consumer_start( consumer ) == 0 )
780                         {
781                                 // Transport functionality
782                                 transport( melt, consumer );
783                                 
784                                 // Stop the consumer
785                                 mlt_consumer_stop( consumer );
786                         }       
787                 }
788                 else if ( store != NULL && store != stdout && name != NULL )
789                 {
790                         fprintf( stderr, "Project saved as %s.\n", name );
791                         fclose( store );
792                 }
793         }
794         else
795         {
796                 show_usage( argv[0] );
797         }
798
799         // Close the producer
800         if ( melt != NULL )
801                 mlt_producer_close( melt );
802
803         // Close the consumer
804         if ( consumer != NULL )
805                 mlt_consumer_close( consumer );
806
807         // Close the factory
808         mlt_profile_close( profile );
809
810 exit_factory:
811                 
812         mlt_factory_close( );
813
814         return 0;
815 }