]> git.sesse.net Git - mlt/blob - src/melt/melt.c
Rename inigo, fezzik, and westley.
[mlt] / src / melt / melt.c
1 /*
2  * inigo.c -- MLT command line utility
3  * Copyright (C) 2002-2008 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sched.h>
25
26 #include <framework/mlt.h>
27
28 #ifdef __DARWIN__
29 #include <SDL.h>
30 #endif
31
32 #include "io.h"
33
34 static void transport_action( mlt_producer producer, char *value )
35 {
36         mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
37         mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL );
38         mlt_consumer consumer = mlt_properties_get_data( properties, "transport_consumer", NULL );
39
40         mlt_properties_set_int( properties, "stats_off", 1 );
41
42         if ( strlen( value ) == 1 )
43         {
44                 switch( value[ 0 ] )
45                 {
46                         case 'q':
47                                 mlt_properties_set_int( properties, "done", 1 );
48                                 break;
49                         case '0':
50                                 mlt_producer_set_speed( producer, 1 );
51                                 mlt_producer_seek( producer, 0 );
52                                 break;
53                         case '1':
54                                 mlt_producer_set_speed( producer, -10 );
55                                 break;
56                         case '2':
57                                 mlt_producer_set_speed( producer, -5 );
58                                 break;
59                         case '3':
60                                 mlt_producer_set_speed( producer, -2 );
61                                 break;
62                         case '4':
63                                 mlt_producer_set_speed( producer, -1 );
64                                 break;
65                         case '5':
66                                 mlt_producer_set_speed( producer, 0 );
67                                 break;
68                         case '6':
69                         case ' ':
70                                 mlt_producer_set_speed( producer, 1 );
71                                 break;
72                         case '7':
73                                 mlt_producer_set_speed( producer, 2 );
74                                 break;
75                         case '8':
76                                 mlt_producer_set_speed( producer, 5 );
77                                 break;
78                         case '9':
79                                 mlt_producer_set_speed( producer, 10 );
80                                 break;
81                         case 'd':
82                                 if ( multitrack != NULL )
83                                 {
84                                         int i = 0;
85                                         mlt_position last = -1;
86                                         fprintf( stderr, "\n" );
87                                         for ( i = 0; 1; i ++ )
88                                         {
89                                                 mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i );
90                                                 if ( time == last )
91                                                         break;
92                                                 last = time;
93                                                 fprintf( stderr, "%d: %d\n", i, (int)time );
94                                         }
95                                 }
96                                 break;
97
98                         case 'g':
99                                 if ( multitrack != NULL )
100                                 {
101                                         mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 );
102                                         mlt_producer_seek( producer, time );
103                                 }
104                                 break;
105                         case 'H':
106                                 if ( producer != NULL )
107                                 {
108                                         mlt_position position = mlt_producer_position( producer );
109                                         mlt_producer_seek( producer, position - ( mlt_producer_get_fps( producer ) * 60 ) );
110                                 }
111                                 break;
112                         case 'h':
113                                 if ( producer != NULL )
114                                 {
115                                         mlt_position position = mlt_producer_position( producer );
116                                         mlt_producer_set_speed( producer, 0 );
117                                         mlt_producer_seek( producer, position - 1 );
118                                 }
119                                 break;
120                         case 'j':
121                                 if ( multitrack != NULL )
122                                 {
123                                         mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 );
124                                         mlt_producer_seek( producer, time );
125                                 }
126                                 break;
127                         case 'k':
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 'l':
135                                 if ( producer != NULL )
136                                 {
137                                         mlt_position position = mlt_producer_position( producer );
138                                         if ( mlt_producer_get_speed( producer ) != 0 )
139                                                 mlt_producer_set_speed( producer, 0 );
140                                         else
141                                                 mlt_producer_seek( producer, position + 1 );
142                                 }
143                                 break;
144                         case 'L':
145                                 if ( producer != NULL )
146                                 {
147                                         mlt_position position = mlt_producer_position( producer );
148                                         mlt_producer_seek( producer, position + ( mlt_producer_get_fps( producer ) * 60 ) );
149                                 }
150                                 break;
151                 }
152
153                 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 );
154         }
155
156         mlt_properties_set_int( properties, "stats_off", 0 );
157 }
158
159 static mlt_consumer create_consumer( mlt_profile profile, char *id )
160 {
161         char *arg = id != NULL ? strchr( id, ':' ) : NULL;
162         if ( arg != NULL )
163                 *arg ++ = '\0';
164         mlt_consumer consumer = mlt_factory_consumer( profile, id, arg );
165         if ( consumer != NULL )
166         {
167                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
168                 mlt_properties_set_data( properties, "transport_callback", transport_action, 0, NULL, NULL );
169         }
170         return consumer;
171 }
172
173 #ifdef __DARWIN__
174
175 static void event_handling( mlt_producer producer, mlt_consumer consumer )
176 {
177         SDL_Event event;
178
179         while ( SDL_PollEvent( &event ) )
180         {
181                 switch( event.type )
182                 {
183                         case SDL_QUIT:
184                                 mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( consumer ), "done", 1 );
185                                 break;
186
187                         case SDL_KEYDOWN:
188                                 if ( event.key.keysym.unicode < 0x80 && event.key.keysym.unicode > 0 )
189                                 {
190                                         char keyboard[ 2 ] = { event.key.keysym.unicode, 0 };
191                                         transport_action( producer, keyboard );
192                                 }
193                                 break;
194                 }
195         }
196 }
197
198 #endif
199
200 static void transport( mlt_producer producer, mlt_consumer consumer )
201 {
202         mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
203         int silent = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "silent" );
204         int progress = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "progress" );
205         struct timespec tm = { 0, 40000 };
206         int total_length = mlt_producer_get_length( producer );
207         int last_position = 0;
208
209         if ( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) )
210         {
211                 if ( !silent && !progress )
212                 {
213                         term_init( );
214
215                         fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" );
216                         fprintf( stderr, "|1=-10| |2= -5| |3= -2| |4= -1| |5=  0| |6=  1| |7=  2| |8=  5| |9= 10|\n" );
217                         fprintf( stderr, "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+\n" );
218
219                         fprintf( stderr, "+---------------------------------------------------------------------+\n" );
220                         fprintf( stderr, "|               H = back 1 minute,  L = forward 1 minute              |\n" );
221                         fprintf( stderr, "|                 h = previous frame,  l = next frame                 |\n" );
222                         fprintf( stderr, "|           g = start of clip, j = next clip, k = previous clip       |\n" );
223                         fprintf( stderr, "|                0 = restart, q = quit, space = play                  |\n" );
224                         fprintf( stderr, "+---------------------------------------------------------------------+\n" );
225                 }
226
227                 while( mlt_properties_get_int( properties, "done" ) == 0 && !mlt_consumer_is_stopped( consumer ) )
228                 {
229                         int value = ( silent || progress )? -1 : term_read( );
230
231                         if ( value != -1 )
232                         {
233                                 char string[ 2 ] = { value, 0 };
234                                 transport_action( producer, string );
235                         }
236
237 #ifdef __DARWIN__
238                         event_handling( producer, consumer );
239 #endif
240
241                         if ( !silent && mlt_properties_get_int( properties, "stats_off" ) == 0 )
242                         {
243                                 if ( progress )
244                                 {
245                                         int current_position = mlt_producer_position( producer );
246                                         if ( current_position > last_position )
247                                         {
248                                                 fprintf( stderr, "Current Frame: %10d, percentage: %10d\r",
249                                                         current_position, 100 * current_position / total_length );
250                                                 last_position = current_position;
251                                         }
252                                 }
253                                 else
254                                 {
255                                         fprintf( stderr, "Current Position: %10d\r", (int)mlt_producer_position( producer ) );
256                                 }
257                         }
258
259                         if ( silent )
260                                 nanosleep( &tm, NULL );
261                 }
262
263                 if ( !silent )
264                         fprintf( stderr, "\n" );
265         }
266 }
267
268 static void query_metadata( mlt_repository repo, mlt_service_type type, const char *typestr, char *id )
269 {
270         mlt_properties metadata = mlt_repository_metadata( repo, type, id );
271         if ( metadata )
272         {
273                 char *s = mlt_properties_serialise_yaml( metadata );
274                 fprintf( stderr, "%s", s );
275                 free( s );
276         }
277         else
278         {
279                 fprintf( stderr, "# No metadata for %s \"%s\"\n", typestr, id );
280         }
281 }
282
283 static void query_services( mlt_repository repo, mlt_service_type type )
284 {
285         mlt_properties services = NULL;
286         const char *typestr = NULL;
287         switch ( type )
288         {
289                 case consumer_type:
290                         services = mlt_repository_consumers( repo );
291                         typestr = "consumers";
292                         break;
293                 case filter_type:
294                         services = mlt_repository_filters( repo );
295                         typestr = "filters";
296                         break;
297                 case producer_type:
298                         services = mlt_repository_producers( repo );
299                         typestr = "producers";
300                         break;
301                 case transition_type:
302                         services = mlt_repository_transitions( repo );
303                         typestr = "transitions";
304                         break;
305                 default:
306                         return;
307         }
308         fprintf( stderr, "---\n%s:\n", typestr );
309         if ( services )
310         {
311                 int j;
312                 for ( j = 0; j < mlt_properties_count( services ); j++ )
313                         fprintf( stderr, "  - %s\n", mlt_properties_get_name( services, j ) );
314         }
315         fprintf( stderr, "...\n" );
316 }
317
318 int main( int argc, char **argv )
319 {
320         int i;
321         mlt_consumer consumer = NULL;
322         mlt_producer inigo = NULL;
323         FILE *store = NULL;
324         char *name = NULL;
325         mlt_profile profile = NULL;
326         int is_progress = 0;
327         int is_silent = 0;
328
329         // Construct the factory
330         mlt_repository repo = mlt_factory_init( NULL );
331
332         for ( i = 1; i < argc; i ++ )
333         {
334                 // Check for serialisation switch
335                 if ( !strcmp( argv[ i ], "-serialise" ) )
336                 {
337                         name = argv[ ++ i ];
338                         if ( name != NULL && strstr( name, ".inigo" ) )
339                                 store = fopen( name, "w" );
340                         else
341                         {
342                                 if ( name == NULL || name[0] == '-' )
343                                         store = stdout;
344                                 name = NULL;
345                         }
346                 }
347                 // Look for the profile option
348                 else if ( !strcmp( argv[ i ], "-profile" ) )
349                 {
350                         const char *pname = argv[ ++ i ];
351                         if ( pname && pname[0] != '-' )
352                                 profile = mlt_profile_init( pname );
353                 }
354                 else if ( !strcmp( argv[ i ], "-progress" ) )
355                 {
356                         is_progress = 1;
357                 }
358                 // Look for the query option
359                 else if ( !strcmp( argv[ i ], "-query" ) )
360                 {
361                         const char *pname = argv[ ++ i ];
362                         if ( pname && pname[0] != '-' )
363                         {
364                                 if ( !strcmp( pname, "consumers" ) || !strcmp( pname, "consumer" ) )
365                                         query_services( repo, consumer_type );
366                                 else if ( !strcmp( pname, "filters" ) || !strcmp( pname, "filter" ) )
367                                         query_services( repo, filter_type );
368                                 else if ( !strcmp( pname, "producers" ) || !strcmp( pname, "producer" ) )
369                                         query_services( repo, producer_type );
370                                 else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) )
371                                         query_services( repo, transition_type );
372                                 
373                                 else if ( !strncmp( pname, "consumer=", 9 ) )
374                                         query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 );
375                                 else if ( !strncmp( pname, "filter=", 7 ) )
376                                         query_metadata( repo, filter_type, "filter", strchr( pname, '=' ) + 1 );
377                                 else if ( !strncmp( pname, "producer=", 9 ) )
378                                         query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 );
379                                 else if ( !strncmp( pname, "transition=", 11 ) )
380                                         query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 );
381                                 else
382                                         goto query_all;
383                         }
384                         else
385                         {
386 query_all:
387                                 query_services( repo, consumer_type );
388                                 query_services( repo, filter_type );
389                                 query_services( repo, producer_type );
390                                 query_services( repo, transition_type );
391                                 fprintf( stderr, "# You can query the metadata for a specific service using:\n"
392                                         "# -query <type>=<identifer>\n"
393                                         "# where <type> is one of: consumer, filter, producer, or transition.\n" );
394                         }
395                         goto exit_factory;
396                 }
397                 else if ( !strcmp( argv[ i ], "-silent" ) )
398                 {
399                         is_silent = 1;
400                 }
401                 else if ( !strcmp( argv[ i ], "-verbose" ) )
402                 {
403                         mlt_log_set_level( MLT_LOG_VERBOSE );
404                 }
405                 else if ( !strcmp( argv[ i ], "-version" ) || !strcmp( argv[ i ], "--version" ) )
406                 {
407                         fprintf( stderr, "MLT inigo " VERSION "\n"
408                                 "Copyright (C) 2002-2008 Ushodaya Enterprises Limited\n"
409                                 "<http://www.mltframework.org/>\n"
410                                 "This is free software; see the source for copying conditions.  There is NO\n"
411                                 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
412                         );
413                         goto exit_factory;
414                 }
415                 else if ( !strcmp( argv[ i ], "-debug" ) )
416                 {
417                         mlt_log_set_level( MLT_LOG_DEBUG );
418                 }
419         }
420
421         // Create profile if not set explicitly
422         if ( profile == NULL )
423                 profile = mlt_profile_init( NULL );
424
425         // Look for the consumer option
426         for ( i = 1; i < argc; i ++ )
427         {
428                 if ( !strcmp( argv[ i ], "-consumer" ) )
429                 {
430                         consumer = create_consumer( profile, argv[ ++ i ] );
431                         if ( consumer )
432                         {
433                                 mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
434                                 while ( argv[ i + 1 ] != NULL && strstr( argv[ i + 1 ], "=" ) )
435                                         mlt_properties_parse( properties, argv[ ++ i ] );
436                         }
437                 }
438         }
439
440         // If we have no consumer, default to sdl
441         if ( store == NULL && consumer == NULL )
442                 consumer = create_consumer( profile, NULL );
443
444         // Get inigo producer
445         if ( argc > 1 )
446                 inigo = mlt_factory_producer( profile, "inigo", &argv[ 1 ] );
447
448         // Set transport properties on consumer and produder
449         if ( consumer != NULL && inigo != NULL )
450         {
451                 mlt_properties_set_data( MLT_CONSUMER_PROPERTIES( consumer ), "transport_producer", inigo, 0, NULL, NULL );
452                 mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( inigo ), "transport_consumer", consumer, 0, NULL, NULL );
453                 if ( is_progress )
454                         mlt_properties_set_int(  MLT_CONSUMER_PROPERTIES( consumer ), "progress", is_progress );
455                 if ( is_silent )
456                         mlt_properties_set_int(  MLT_CONSUMER_PROPERTIES( consumer ), "silent", is_silent );
457         }
458
459         if ( argc > 1 && inigo != NULL && mlt_producer_get_length( inigo ) > 0 )
460         {
461                 // Parse the arguments
462                 for ( i = 1; i < argc; i ++ )
463                 {
464                         if ( !strcmp( argv[ i ], "-serialise" ) )
465                         {
466                                 if ( store != stdout )
467                                         i ++;
468                         }
469                         else
470                         {
471                                 if ( store != NULL )
472                                         fprintf( store, "%s\n", argv[ i ] );
473
474                                 i ++;
475
476                                 while ( argv[ i ] != NULL && argv[ i ][ 0 ] != '-' )
477                                 {
478                                         if ( store != NULL )
479                                                 fprintf( store, "%s\n", argv[ i ] );
480                                         i += 1;
481                                 }
482
483                                 i --;
484                         }
485                 }
486
487                 if ( consumer != NULL && store == NULL )
488                 {
489                         // Get inigo's properties
490                         mlt_properties inigo_props = MLT_PRODUCER_PROPERTIES( inigo );
491         
492                         // Get the last group
493                         mlt_properties group = mlt_properties_get_data( inigo_props, "group", 0 );
494         
495                         // Apply group settings
496                         mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
497                         mlt_properties_inherit( properties, group );
498
499                         // Connect consumer to inigo
500                         mlt_consumer_connect( consumer, MLT_PRODUCER_SERVICE( inigo ) );
501
502                         // Start the consumer
503                         mlt_consumer_start( consumer );
504
505                         // Transport functionality
506                         transport( inigo, consumer );
507
508                         // Stop the consumer
509                         mlt_consumer_stop( consumer );
510                 }
511                 else if ( store != NULL && store != stdout && name != NULL )
512                 {
513                         fprintf( stderr, "Project saved as %s.\n", name );
514                         fclose( store );
515                 }
516         }
517         else
518         {
519                 fprintf( stderr,
520 "Usage: inigo [options] [producer [name=value]* ]+\n"
521 "Options:\n"
522 "  -attach filter[:arg] [name=value]*       Attach a filter to the output\n"
523 "  -attach-cut filter[:arg] [name=value]*   Attach a filter to a cut\n"
524 "  -attach-track filter[:arg] [name=value]* Attach a filter to a track\n"
525 "  -attach-clip filter[:arg] [name=value]*  Attach a filter to a producer\n"
526 "  -audio-track | -hide-video               Add an audio-only track\n"
527 "  -blank frames                            Add blank silence to a track\n"
528 "  -consumer id[:arg] [name=value]*         Set the consumer (sink)\n"
529 "  -debug                                   Set the logging level to debug\n"
530 "  -filter filter[:arg] [name=value]*       Add a filter to the current track\n"
531 "  -group [name=value]*                     Apply properties repeatedly\n"
532 "  -help                                    Show this message\n"
533 "  -join clips                              Join multiple clips into one cut\n"
534 "  -mix length                              Add a mix between the last two cuts\n"
535 "  -mixer transition                        Add a transition to the mix\n"
536 "  -null-track | -hide-track                Add a hidden track\n"
537 "  -profile name                            Set the processing settings\n"
538 "  -progress                                Display progress along with position\n"
539 "  -remove                                  Remove the most recent cut\n"
540 "  -repeat times                            Repeat the last cut\n"
541 "  -query                                   List all of the registered services\n"
542 "  -query \"consumers\" | \"consumer\"=id       List consumers or show info about one\n"
543 "  -query \"filters\" | \"filter\"=id           List filters or show info about one\n"
544 "  -query \"producers\" | \"producer\"=id       List producers or show info about one\n"
545 "  -query \"transitions\" | \"transition\"=id   List transitions, show info about one\n"
546 "  -serialise [filename]                    Write the commands to a text file\n"
547 "  -silent                                  Do not display position/transport\n"
548 "  -split relative-frame                    Split the last cut into two cuts\n"
549 "  -swap                                    Rearrange the last two cuts\n"
550 "  -track                                   Add a track\n"
551 "  -transition id[:arg] [name=value]*       Add a transition\n"
552 "  -verbose                                 Set the logging level to verbose\n"
553 "  -version                                 Show the version and copyright\n"
554 "  -video-track | -hide-audio               Add a video-only track\n"
555 "For more help: <http://www.mltframework.org/>\n" );
556         }
557
558         // Close the consumer
559         if ( consumer != NULL )
560                 mlt_consumer_close( consumer );
561
562         // Close the producer
563         if ( inigo != NULL )
564                 mlt_producer_close( inigo );
565
566         // Close the factory
567         mlt_profile_close( profile );
568
569 exit_factory:
570                 
571         mlt_factory_close( );
572
573         return 0;
574 }