OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / test / test.c
1 /* $Id: test.c,v 1.82 2005/11/19 08:25:54 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include <signal.h>
8 #include <getopt.h>
9 #include <sys/time.h>
10 #include <time.h>
11 #include <unistd.h>
12 #include <inttypes.h>
13
14 #if defined( __MINGW32__ )
15 #include <conio.h>
16 #endif
17
18 #if defined( PTW32_STATIC_LIB )
19 #include <pthread.h>
20 #endif
21
22 #include "hb.h"
23 #include "parsecsv.h"
24
25 #if defined( __APPLE_CC__ )
26 #import <CoreServices/CoreServices.h>
27 #include <IOKit/IOKitLib.h>
28 #include <IOKit/storage/IOMedia.h>
29 #include <IOKit/storage/IODVDMedia.h>
30 #endif
31
32 /* Options */
33 #if defined( __APPLE_CC__ )
34 #define EXTRA_VLC_DYLD_PATH "/Applications/VLC.app/Contents/MacOS/lib"
35 #define DEFAULT_DYLD_PATH "/usr/local/lib:/usr/lib"
36
37 static int    no_vlc_dylib = 0;
38 #endif
39 static int    debug       = HB_DEBUG_ALL;
40 static int    update      = 0;
41 static int    dvdnav      = 1;
42 static char * input       = NULL;
43 static char * output      = NULL;
44 static char * format      = NULL;
45 static int    titleindex  = 1;
46 static int    titlescan   = 0;
47 static int    main_feature = 0;
48 static char * native_language = NULL;
49 static int    native_dub  = 0;
50 static int    twoPass     = 0;
51 static int    deinterlace           = 0;
52 static char * deinterlace_opt       = 0;
53 static int    deblock               = 0;
54 static char * deblock_opt           = 0;
55 static int    denoise               = 0;
56 static char * denoise_opt           = 0;
57 static int    detelecine            = 0;
58 static char * detelecine_opt        = 0;
59 static int    decomb                = 0;
60 static char * decomb_opt            = 0;
61 static int    rotate                = 0;
62 static char * rotate_opt            = 0;
63 static int    grayscale   = 0;
64 static int    vcodec      = HB_VCODEC_FFMPEG;
65 static hb_list_t * audios = NULL;
66 static hb_audio_config_t * audio = NULL;
67 static int    num_audio_tracks = 0;
68 static char * mixdowns    = NULL;
69 static char * dynamic_range_compression = NULL;
70 static char * atracks     = NULL;
71 static char * arates      = NULL;
72 static char * abitrates   = NULL;
73 static char * acodecs     = NULL;
74 static char * anames      = NULL;
75 #ifdef __APPLE_CC__
76 static int    default_acodec = HB_ACODEC_CA_AAC;
77 #else
78 static int    default_acodec = HB_ACODEC_FAAC;
79 #endif
80 static int    audio_explicit = 0;
81 static char ** subtracks   = NULL;
82 static char ** subforce    = NULL;
83 static char * subburn     = NULL;
84 static char * subdefault  = NULL;
85 static char ** srtfile     = NULL;
86 static char ** srtcodeset  = NULL;
87 static char ** srtoffset   = NULL;
88 static char ** srtlang     = NULL;
89 static int     srtdefault  = -1;
90 static int    subtitle_scan = 0;
91 static int    width       = 0;
92 static int    height      = 0;
93 static int    crop[4]     = { -1,-1,-1,-1 };
94 static int    cpu         = 0;
95 static int    vrate       = 0;
96 static float  vquality    = -1.0;
97 static int    vbitrate    = 0;
98 static int    size        = 0;
99 static int    mux         = 0;
100 static int    anamorphic_mode  = 0;
101 static int    modulus       = 0;
102 static int    par_height    = 0;
103 static int    par_width     = 0;
104 static int    display_width = 0;
105 static int    keep_display_aspect = 0;
106 static int    itu_par       = 0;
107 static int    angle = 0;
108 static int    chapter_start = 0;
109 static int    chapter_end   = 0;
110 static int    chapter_markers = 0;
111 static char * marker_file   = NULL;
112 static char       *x264opts             = NULL;
113 static char       *x264opts2    = NULL;
114 static int        maxHeight             = 0;
115 static int        maxWidth              = 0;
116 static int    turbo_opts_enabled = 0;
117 static char * turbo_opts = "ref=1:subme=2:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0";
118 static int    largeFileSize = 0;
119 static int    preset        = 0;
120 static char * preset_name   = 0;
121 static int    cfr           = 0;
122 static int    mp4_optimize  = 0;
123 static int    ipod_atom     = 0;
124 static int    color_matrix  = 0;
125 static int    preview_count = 10;
126 static int    store_previews = 0;
127 static int    start_at_preview = 0;
128 static int64_t start_at_pts    = 0;
129 static int    start_at_frame = 0;
130 static char * start_at_string = NULL;
131 static char * start_at_token = NULL;
132 static int64_t stop_at_pts    = 0;
133 static int    stop_at_frame = 0;
134 static char * stop_at_string = NULL;
135 static char * stop_at_token = NULL;
136 static uint64_t min_title_duration = 900000LL;
137
138 /* Exit cleanly on Ctrl-C */
139 static volatile int die = 0;
140 static void SigHandler( int );
141
142 /* Utils */
143 static void ShowCommands();
144 static void ShowHelp();
145 static void ShowPresets();
146
147 static int  ParseOptions( int argc, char ** argv );
148 static int  CheckOptions( int argc, char ** argv );
149 static int  HandleEvents( hb_handle_t * h );
150
151 static int get_acodec_for_string( char *codec );
152 static int is_sample_rate_valid(int rate);
153
154 #ifdef __APPLE_CC__
155 static char* bsd_name_for_path(char *path);
156 static int device_is_dvd(char *device);
157 static io_service_t get_iokit_service( char *device );
158 static int is_dvd_service( io_service_t service );
159 static int is_whole_media_service( io_service_t service );
160 #endif
161
162 /* Only print the "Muxing..." message once */
163 static int show_mux_warning = 1;
164
165 /****************************************************************************
166  * hb_error_handler
167  *
168  * When using the CLI just display using hb_log as we always did in the past
169  * make sure that we prefix with a nice ERROR message to catch peoples eyes.
170  ****************************************************************************/
171 static void hb_cli_error_handler ( const char *errmsg )
172 {
173     fprintf( stderr, "ERROR: %s\n", errmsg );
174 }
175
176 int main( int argc, char ** argv )
177 {
178     hb_handle_t * h;
179     int           build;
180     char        * version;
181
182 /* win32 _IOLBF (line-buffering) is the same as _IOFBF (full-buffering).
183  * force it to unbuffered otherwise informative output is not easily parsed.
184  */
185 #if defined( _WIN32 ) || defined( __MINGW32__ )
186     setvbuf( stdout, NULL, _IONBF, 0 );
187     setvbuf( stderr, NULL, _IONBF, 0 );
188 #endif
189
190     audios = hb_list_init();
191
192     /* Parse command line */
193     if( ParseOptions( argc, argv ) ||
194         CheckOptions( argc, argv ) )
195     {
196         return 1;
197     }
198
199     /* Register our error handler */
200     hb_register_error_handler(&hb_cli_error_handler);
201
202     /* Init libhb */
203     h = hb_init( debug, update );
204     hb_dvd_set_dvdnav( dvdnav );
205
206     /* Show version */
207     fprintf( stderr, "%s - %s - %s\n",
208              HB_PROJECT_TITLE, HB_PROJECT_BUILD_TITLE, HB_PROJECT_URL_WEBSITE );
209
210     /* Check for update */
211     if( update )
212     {
213         if( ( build = hb_check_update( h, &version ) ) > -1 )
214         {
215             fprintf( stderr, "You are using an old version of "
216                      "HandBrake.\nLatest is %s (build %d).\n", version,
217                      build );
218         }
219         else
220         {
221             fprintf( stderr, "Your version of HandBrake is up to "
222                      "date.\n" );
223         }
224         hb_close( &h );
225         hb_global_close();
226         return 0;
227     }
228
229     /* Geeky */
230     fprintf( stderr, "%d CPU%s detected\n", hb_get_cpu_count(),
231              hb_get_cpu_count( h ) > 1 ? "s" : "" );
232     if( cpu )
233     {
234         fprintf( stderr, "Forcing %d CPU%s\n", cpu,
235                  cpu > 1 ? "s" : "" );
236         hb_set_cpu_count( h, cpu );
237     }
238
239     /* Exit ASAP on Ctrl-C */
240     signal( SIGINT, SigHandler );
241
242     /* Feed libhb with a DVD to scan */
243     fprintf( stderr, "Opening %s...\n", input );
244
245     if (main_feature) {
246         /*
247          * We need to scan for all the titles in order to find the main feature
248          */
249         titleindex = 0;
250     }
251
252     hb_scan( h, input, titleindex, preview_count, store_previews, min_title_duration );
253
254     /* Wait... */
255     while( !die )
256     {
257 #if defined( __MINGW32__ )
258         if( _kbhit() ) {
259             switch( _getch() )
260             {
261                 case 0x03: /* ctrl-c */
262                 case 'q':
263                     fprintf( stdout, "\nEncoding Quit by user command\n" );
264                     die = 1;
265                     break;
266                 case 'p':
267                     fprintf( stdout, "\nEncoding Paused by user command, 'r' to resume\n" );
268                     hb_pause( h );
269                     break;
270                 case 'r':
271                     hb_resume( h );
272                     break;
273                 case 'h':
274                     ShowCommands();
275                     break;
276             }
277         }
278         hb_snooze( 200 );
279 #elif !defined(SYS_BEOS)
280         fd_set         fds;
281         struct timeval tv;
282         int            ret;
283         char           buf[257];
284
285         tv.tv_sec  = 0;
286         tv.tv_usec = 100000;
287
288         FD_ZERO( &fds );
289         FD_SET( STDIN_FILENO, &fds );
290         ret = select( STDIN_FILENO + 1, &fds, NULL, NULL, &tv );
291
292         if( ret > 0 )
293         {
294             int size = 0;
295
296             while( size < 256 &&
297                    read( STDIN_FILENO, &buf[size], 1 ) > 0 )
298             {
299                 if( buf[size] == '\n' )
300                 {
301                     break;
302                 }
303                 size++;
304             }
305
306             if( size >= 256 || buf[size] == '\n' )
307             {
308                 switch( buf[0] )
309                 {
310                     case 'q':
311                         fprintf( stdout, "\nEncoding Quit by user command\n" );
312                         die = 1;
313                         break;
314                     case 'p':
315                         fprintf( stdout, "\nEncoding Paused by user command, 'r' to resume\n" );
316                         hb_pause( h );
317                         break;
318                     case 'r':
319                         hb_resume( h );
320                         break;
321                     case 'h':
322                         ShowCommands();
323                         break;
324                 }
325             }
326         }
327         hb_snooze( 200 );
328 #else
329         hb_snooze( 200 );
330 #endif
331
332         HandleEvents( h );
333     }
334
335     /* Clean up */
336     hb_close( &h );
337     hb_global_close();
338     if( input )  free( input );
339     if( output ) free( output );
340     if( format ) free( format );
341     if( audios )
342     {
343         while( ( audio = hb_list_item( audios, 0 ) ) )
344         {
345             hb_list_rem( audios, audio );
346             if( audio->out.name )
347             {
348                 free( audio->out.name );
349             }
350             free( audio );
351         }
352         hb_list_close( &audios );
353     }
354     if( mixdowns ) free( mixdowns );
355     if( dynamic_range_compression ) free( dynamic_range_compression );
356     if( atracks ) free( atracks );
357     if( arates ) free( arates );
358     if( abitrates ) free( abitrates );
359     if( acodecs ) free( acodecs );
360     if( anames ) free( anames );
361     if (native_language ) free (native_language );
362         if( x264opts ) free (x264opts );
363         if( x264opts2 ) free (x264opts2 );
364     if (preset_name) free (preset_name);
365     if( stop_at_string ) free( stop_at_string );
366     if( start_at_string ) free( start_at_string );
367
368     // write a carriage return to stdout - avoids overlap / line wrapping when stderr is redirected
369     fprintf( stdout, "\n" );
370     fprintf( stderr, "HandBrake has exited.\n" );
371
372     return 0;
373 }
374
375 static void ShowCommands()
376 {
377     fprintf( stdout, "\nCommands:\n" );
378     fprintf( stdout, " [h]elp    Show this message\n" );
379     fprintf( stdout, " [q]uit    Exit HandBrakeCLI\n" );
380     fprintf( stdout, " [p]ause   Pause encoding\n" );
381     fprintf( stdout, " [r]esume  Resume encoding\n" );
382 }
383
384 static void PrintTitleInfo( hb_title_t * title )
385 {
386     hb_chapter_t  * chapter;
387     hb_subtitle_t * subtitle;
388     int i;
389
390     fprintf( stderr, "+ title %d:\n", title->index );
391     if ( title->index == title->job->feature )
392     {
393         fprintf( stderr, "  + Main Feature\n" );
394     }
395     if ( title->type == HB_STREAM_TYPE )
396     {
397         fprintf( stderr, "  + stream: %s\n", title->path );
398     }
399     else if ( title->type == HB_DVD_TYPE )
400     {
401         fprintf( stderr, "  + vts %d, ttn %d, cells %d->%d (%"PRIu64" blocks)\n",
402                 title->vts, title->ttn, title->cell_start, title->cell_end,
403                 title->block_count );
404     }
405     if (title->angle_count > 1)
406         fprintf( stderr, "  + angle(s) %d\n", title->angle_count );
407     fprintf( stderr, "  + duration: %02d:%02d:%02d\n",
408              title->hours, title->minutes, title->seconds );
409     fprintf( stderr, "  + size: %dx%d, pixel aspect: %d/%d, display aspect: %.2f, %.3f fps\n",
410              title->width, title->height,
411              title->pixel_aspect_width,
412              title->pixel_aspect_height,
413              (float) title->aspect,
414              (float) title->rate / title->rate_base );
415     fprintf( stderr, "  + autocrop: %d/%d/%d/%d\n", title->crop[0],
416              title->crop[1], title->crop[2], title->crop[3] );
417     fprintf( stderr, "  + chapters:\n" );
418     for( i = 0; i < hb_list_count( title->list_chapter ); i++ )
419     {
420         chapter = hb_list_item( title->list_chapter, i );
421         fprintf( stderr, "    + %d: cells %d->%d, %"PRIu64" blocks, duration "
422                  "%02d:%02d:%02d\n", chapter->index,
423                  chapter->cell_start, chapter->cell_end,
424                  chapter->block_count, chapter->hours, chapter->minutes,
425                  chapter->seconds );
426     }
427     fprintf( stderr, "  + audio tracks:\n" );
428     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
429     {
430         audio = hb_list_audio_config_item( title->list_audio, i );
431         if( ( audio->in.codec == HB_ACODEC_AC3 ) || ( audio->in.codec == HB_ACODEC_DCA) )
432         {
433             fprintf( stderr, "    + %d, %s (iso639-2: %s), %dHz, %dbps\n", 
434                      i + 1,
435                      audio->lang.description, 
436                      audio->lang.iso639_2,
437                      audio->in.samplerate, 
438                      audio->in.bitrate );
439         }
440         else
441         {
442             fprintf( stderr, "    + %d, %s (iso639-2: %s)\n", 
443                      i + 1, 
444                      audio->lang.description,
445                      audio->lang.iso639_2 );
446         }
447     }
448     fprintf( stderr, "  + subtitle tracks:\n" );
449     for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
450     {
451         subtitle = hb_list_item( title->list_subtitle, i );
452         fprintf( stderr, "    + %d, %s (iso639-2: %s) (%s)(%s)\n", 
453                  i + 1, subtitle->lang,
454                  subtitle->iso639_2,
455                  (subtitle->format == TEXTSUB) ? "Text" : "Bitmap",
456                  hb_subsource_name(subtitle->source));
457     }
458
459     if(title->detected_interlacing)
460     {
461         /* Interlacing was found in half or more of the preview frames */
462         fprintf( stderr, "  + combing detected, may be interlaced or telecined\n");
463     }
464
465 }
466
467 static int test_sub_list( char ** list, int pos )
468 {
469     int i;
470
471     if ( list == NULL || pos == 0 )
472         return 0;
473
474     if ( list[0] == NULL && pos == 1 )
475         return 1;
476
477     for ( i = 0; list[i] != NULL; i++ )
478     {
479         int idx = strtol( list[i], NULL, 0 );
480         if ( idx == pos )
481             return 1;
482     }
483     return 0;
484 }
485
486 static int HandleEvents( hb_handle_t * h )
487 {
488     hb_state_t s;
489     int tmp_num_audio_tracks;
490
491     hb_get_state( h, &s );
492     switch( s.state )
493     {
494         case HB_STATE_IDLE:
495             /* Nothing to do */
496             break;
497
498 #define p s.param.scanning
499         case HB_STATE_SCANNING:
500             /* Show what title is currently being scanned */
501             fprintf( stderr, "Scanning title %d", p.title_cur );
502             if( !titleindex || titlescan )
503                 fprintf( stderr, " of %d", p.title_count );
504             fprintf( stderr, "...\n" );
505             break;
506 #undef p
507
508         case HB_STATE_SCANDONE:
509         {
510             hb_list_t  * list;
511             hb_title_t * title;
512             hb_job_t   * job;
513             int i;
514             int sub_burned = 0;
515
516             /* Audio argument string parsing variables */
517             int acodec = 0;
518             int abitrate = 0;
519             int arate = 0;
520             int mixdown = HB_AMIXDOWN_DOLBYPLII;
521             double d_r_c = 0;
522             /* Audio argument string parsing variables */
523
524             list = hb_get_titles( h );
525
526             if( !hb_list_count( list ) )
527             {
528                 /* No valid title, stop right there */
529                 fprintf( stderr, "No title found.\n" );
530                 die = 1;
531                 break;
532             }
533                 if( main_feature )
534                 {
535                 int i;
536                 int main_feature_idx=0;
537                 int main_feature_pos=-1;
538                 int main_feature_time=0;
539                 int title_time;
540
541                 fprintf( stderr, "Searching for main feature title...\n" );
542
543                 for( i = 0; i < hb_list_count( list ); i++ )
544                 {
545                     title = hb_list_item( list, i );
546                     title_time = (title->hours*60*60 ) + (title->minutes *60) + (title->seconds);
547                     fprintf( stderr, " + Title (%d) index %d has length %dsec\n",
548                              i, title->index, title_time );
549                     if( main_feature_time < title_time )
550                     {
551                         main_feature_time = title_time;
552                         main_feature_pos = i;
553                         main_feature_idx = title->index;
554                     }
555                     if( title->job->feature == title->index )
556                     {
557                         main_feature_time = title_time;
558                         main_feature_pos = i;
559                         main_feature_idx = title->index;
560                         break;
561                     }
562                 }
563                 if( main_feature_pos == -1 )
564                 {
565                     fprintf( stderr, "No main feature title found.\n" );
566                     die = 1;
567                     break;
568                 }
569                 titleindex = main_feature_idx;
570                 fprintf( stderr, "Found main feature title, setting title to %d\n",
571                          main_feature_idx);
572
573                 title = hb_list_item( list, main_feature_pos);
574             } else {
575                 title = hb_list_item( list, 0 );
576             }
577
578             if( !titleindex || titlescan )
579             {
580                 /* Scan-only mode, print infos and exit */
581                 int i;
582                 for( i = 0; i < hb_list_count( list ); i++ )
583                 {
584                     title = hb_list_item( list, i );
585                     PrintTitleInfo( title );
586                 }
587                 die = 1;
588                 break;
589             }
590
591             /* Set job settings */
592             job   = title->job;
593
594             PrintTitleInfo( title );
595
596             if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame )
597             {
598                 job->chapter_start = MAX( job->chapter_start,
599                                           chapter_start );
600                 job->chapter_end   = MIN( job->chapter_end,
601                                           chapter_end );
602                 job->chapter_end   = MAX( job->chapter_start,
603                                           job->chapter_end );
604             }
605
606             if ( angle )
607             {
608                 job->angle = angle;
609             }
610
611             if (preset)
612             {
613                 fprintf( stderr, "+ Using preset: %s\n", preset_name);
614
615                 if (!strcmp(preset_name, "Universal"))
616                                 {
617                                         if( !mux )
618                                         {
619                                                 mux = HB_MUX_MP4;
620                                         }
621                                         vcodec = HB_VCODEC_X264;
622                                         job->vquality = 20.0;
623                                         if( !atracks )
624                                         {
625                                                 atracks = strdup("1,1");
626                                         }
627                                         if( !acodecs )
628                                         {
629                                                 acodecs = strdup("faac,copy:ac3");
630                                         }
631                                         if( !abitrates )
632                                         {
633                                                 abitrates = strdup("160,160");
634                                         }
635                                         if( !mixdowns )
636                                         {
637                                                 mixdowns = strdup("dpl2,auto");
638                                         }
639                                         if( !arates )
640                                         {
641                                                 arates = strdup("Auto,Auto");
642                                         }
643                                         if( !dynamic_range_compression )
644                                         {
645                                                 dynamic_range_compression = strdup("0.0,0.0");
646                                         }
647                                         maxWidth = 720;
648                                         if( !x264opts )
649                                         {
650                                                 x264opts = strdup("cabac=0:ref=2:me=umh:bframes=0:weightp=0:8x8dct=0:trellis=0:subme=6");
651                                         }
652                                         if( !anamorphic_mode )
653                                         {
654                                                 anamorphic_mode = 2;
655                                         }
656                                         job->chapter_markers = 1;
657                                         
658                                 }
659                                 
660                                 if (!strcmp(preset_name, "iPod"))
661                                 {
662                                         if( !mux )
663                                         {
664                                                 mux = HB_MUX_MP4;
665                                         }
666                                         job->ipod_atom = 1;
667                                         vcodec = HB_VCODEC_X264;
668                                         job->vbitrate = 700;
669                                         if( !atracks )
670                                         {
671                                                 atracks = strdup("1");
672                                         }
673                                         if( !acodecs )
674                                         {
675                                                 acodecs = strdup("faac");
676                                         }
677                                         if( !abitrates )
678                                         {
679                                                 abitrates = strdup("160");
680                                         }
681                                         if( !mixdowns )
682                                         {
683                                                 mixdowns = strdup("dpl2");
684                                         }
685                                         if( !arates )
686                                         {
687                                                 arates = strdup("Auto");
688                                         }
689                                         if( !dynamic_range_compression )
690                                         {
691                                                 dynamic_range_compression = strdup("0.0");
692                                         }
693                                         maxWidth = 320;
694                                         if( !x264opts )
695                                         {
696                                                 x264opts = strdup("level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:subme=6:8x8dct=0:trellis=0");
697                                         }
698                                         job->chapter_markers = 1;
699                                         
700                                 }
701                                 
702                                 if (!strcmp(preset_name, "iPhone & iPod Touch"))
703                                 {
704                                         if( !mux )
705                                         {
706                                                 mux = HB_MUX_MP4;
707                                         }
708                                         vcodec = HB_VCODEC_X264;
709                                         job->vquality = 20.0;
710                                         if( !atracks )
711                                         {
712                                                 atracks = strdup("1");
713                                         }
714                                         if( !acodecs )
715                                         {
716                                                 acodecs = strdup("faac");
717                                         }
718                                         if( !abitrates )
719                                         {
720                                                 abitrates = strdup("128");
721                                         }
722                                         if( !mixdowns )
723                                         {
724                                                 mixdowns = strdup("dpl2");
725                                         }
726                                         if( !arates )
727                                         {
728                                                 arates = strdup("Auto");
729                                         }
730                                         if( !dynamic_range_compression )
731                                         {
732                                                 dynamic_range_compression = strdup("0.0");
733                                         }
734                                         maxWidth = 480;
735                                         if( !x264opts )
736                                         {
737                                                 x264opts = strdup("cabac=0:ref=2:me=umh:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0");
738                                         }
739                                         job->chapter_markers = 1;
740                                         
741                                 }
742                                 
743                                 if (!strcmp(preset_name, "iPhone 4"))
744                                 {
745                                         if( !mux )
746                                         {
747                                                 mux = HB_MUX_MP4;
748                                         }
749                                         job->largeFileSize = 1;
750                                         vcodec = HB_VCODEC_X264;
751                                         job->vquality = 20.0;
752                                         job->vrate_base = 900900;
753                                         job->cfr = 2;
754                                         if( !atracks )
755                                         {
756                                                 atracks = strdup("1");
757                                         }
758                                         if( !acodecs )
759                                         {
760                                                 acodecs = strdup("faac");
761                                         }
762                                         if( !abitrates )
763                                         {
764                                                 abitrates = strdup("160");
765                                         }
766                                         if( !mixdowns )
767                                         {
768                                                 mixdowns = strdup("dpl2");
769                                         }
770                                         if( !arates )
771                                         {
772                                                 arates = strdup("Auto");
773                                         }
774                                         if( !dynamic_range_compression )
775                                         {
776                                                 dynamic_range_compression = strdup("0.0");
777                                         }
778                                         maxWidth = 960;
779                                         if( !anamorphic_mode )
780                                         {
781                                                 anamorphic_mode = 2;
782                                         }
783                                         job->chapter_markers = 1;
784                                         
785                                 }
786                                 
787                                 if (!strcmp(preset_name, "iPad"))
788                                 {
789                                         if( !mux )
790                                         {
791                                                 mux = HB_MUX_MP4;
792                                         }
793                                         job->largeFileSize = 1;
794                                         vcodec = HB_VCODEC_X264;
795                                         job->vquality = 20.0;
796                                         job->vrate_base = 900900;
797                                         job->cfr = 2;
798                                         if( !atracks )
799                                         {
800                                                 atracks = strdup("1");
801                                         }
802                                         if( !acodecs )
803                                         {
804                                                 acodecs = strdup("faac");
805                                         }
806                                         if( !abitrates )
807                                         {
808                                                 abitrates = strdup("160");
809                                         }
810                                         if( !mixdowns )
811                                         {
812                                                 mixdowns = strdup("dpl2");
813                                         }
814                                         if( !arates )
815                                         {
816                                                 arates = strdup("Auto");
817                                         }
818                                         if( !dynamic_range_compression )
819                                         {
820                                                 dynamic_range_compression = strdup("0.0");
821                                         }
822                                         maxWidth = 1024;
823                                         if( !anamorphic_mode )
824                                         {
825                                                 anamorphic_mode = 2;
826                                         }
827                                         job->chapter_markers = 1;
828                                         
829                                 }
830                                 
831                                 if (!strcmp(preset_name, "AppleTV"))
832                                 {
833                                         if( !mux )
834                                         {
835                                                 mux = HB_MUX_MP4;
836                                         }
837                                         job->largeFileSize = 1;
838                                         vcodec = HB_VCODEC_X264;
839                                         job->vquality = 20.0;
840                                         if( !atracks )
841                                         {
842                                                 atracks = strdup("1,1");
843                                         }
844                                         if( !acodecs )
845                                         {
846                                                 acodecs = strdup("faac,copy:ac3");
847                                         }
848                                         if( !abitrates )
849                                         {
850                                                 abitrates = strdup("160,160");
851                                         }
852                                         if( !mixdowns )
853                                         {
854                                                 mixdowns = strdup("dpl2,auto");
855                                         }
856                                         if( !arates )
857                                         {
858                                                 arates = strdup("Auto,Auto");
859                                         }
860                                         if( !dynamic_range_compression )
861                                         {
862                                                 dynamic_range_compression = strdup("0.0,0.0");
863                                         }
864                                         maxWidth = 960;
865                                         if( !x264opts )
866                                         {
867                                                 x264opts = strdup("cabac=0:ref=2:me=umh:b-pyramid=none:b-adapt=2:weightb=0:trellis=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500");
868                                         }
869                                         if( !anamorphic_mode )
870                                         {
871                                                 anamorphic_mode = 2;
872                                         }
873                                         job->chapter_markers = 1;
874                                         
875                                 }
876                                 
877                                 if (!strcmp(preset_name, "AppleTV 2"))
878                                 {
879                                         if( !mux )
880                                         {
881                                                 mux = HB_MUX_MP4;
882                                         }
883                                         job->largeFileSize = 1;
884                                         vcodec = HB_VCODEC_X264;
885                                         job->vquality = 20.0;
886                                         job->vrate_base = 900900;
887                                         job->cfr = 2;
888                                         if( !atracks )
889                                         {
890                                                 atracks = strdup("1,1");
891                                         }
892                                         if( !acodecs )
893                                         {
894                                                 acodecs = strdup("faac,copy:ac3");
895                                         }
896                                         if( !abitrates )
897                                         {
898                                                 abitrates = strdup("160,160");
899                                         }
900                                         if( !mixdowns )
901                                         {
902                                                 mixdowns = strdup("dpl2,auto");
903                                         }
904                                         if( !arates )
905                                         {
906                                                 arates = strdup("Auto,Auto");
907                                         }
908                                         if( !dynamic_range_compression )
909                                         {
910                                                 dynamic_range_compression = strdup("0.0,0.0");
911                                         }
912                                         maxWidth = 1280;
913                                         if( !anamorphic_mode )
914                                         {
915                                                 anamorphic_mode = 2;
916                                         }
917                                         job->chapter_markers = 1;
918                                         
919                                 }
920                                 
921                                 if (!strcmp(preset_name, "Normal"))
922                                 {
923                                         if( !mux )
924                                         {
925                                                 mux = HB_MUX_MP4;
926                                         }
927                                         vcodec = HB_VCODEC_X264;
928                                         job->vquality = 20.0;
929                                         if( !atracks )
930                                         {
931                                                 atracks = strdup("1");
932                                         }
933                                         if( !acodecs )
934                                         {
935                                                 acodecs = strdup("faac");
936                                         }
937                                         if( !abitrates )
938                                         {
939                                                 abitrates = strdup("160");
940                                         }
941                                         if( !mixdowns )
942                                         {
943                                                 mixdowns = strdup("dpl2");
944                                         }
945                                         if( !arates )
946                                         {
947                                                 arates = strdup("Auto");
948                                         }
949                                         if( !dynamic_range_compression )
950                                         {
951                                                 dynamic_range_compression = strdup("0.0");
952                                         }
953                                         if( !x264opts )
954                                         {
955                                                 x264opts = strdup("ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0");
956                                         }
957                                         if( !anamorphic_mode )
958                                         {
959                                                 anamorphic_mode = 1;
960                                         }
961                                         job->chapter_markers = 1;
962                                         
963                                 }
964                                 
965                                 if (!strcmp(preset_name, "High Profile"))
966                                 {
967                                         if( !mux )
968                                         {
969                                                 mux = HB_MUX_MP4;
970                                         }
971                                         vcodec = HB_VCODEC_X264;
972                                         job->vquality = 20.0;
973                                         if( !atracks )
974                                         {
975                                                 atracks = strdup("1,1");
976                                         }
977                                         if( !acodecs )
978                                         {
979                                                 acodecs = strdup("faac,copy:ac3");
980                                         }
981                                         if( !abitrates )
982                                         {
983                                                 abitrates = strdup("160,160");
984                                         }
985                                         if( !mixdowns )
986                                         {
987                                                 mixdowns = strdup("dpl2,auto");
988                                         }
989                                         if( !arates )
990                                         {
991                                                 arates = strdup("Auto,Auto");
992                                         }
993                                         if( !dynamic_range_compression )
994                                         {
995                                                 dynamic_range_compression = strdup("0.0,0.0");
996                                         }
997                                         if( !x264opts )
998                                         {
999                                                 x264opts = strdup("b-adapt=2:rc-lookahead=50");
1000                                         }
1001                                         detelecine = 1;
1002                                         decomb = 1;
1003                                         if( !anamorphic_mode )
1004                                         {
1005                                                 anamorphic_mode = 2;
1006                                         }
1007                                         job->chapter_markers = 1;
1008                                         
1009                                 }
1010                                 
1011                                 if (!strcmp(preset_name, "Classic"))
1012                                 {
1013                                         if( !mux )
1014                                         {
1015                                                 mux = HB_MUX_MP4;
1016                                         }
1017                                         job->vbitrate = 1000;
1018                                         if( !atracks )
1019                                         {
1020                                                 atracks = strdup("1");
1021                                         }
1022                                         if( !acodecs )
1023                                         {
1024                                                 acodecs = strdup("faac");
1025                                         }
1026                                         if( !abitrates )
1027                                         {
1028                                                 abitrates = strdup("160");
1029                                         }
1030                                         if( !mixdowns )
1031                                         {
1032                                                 mixdowns = strdup("dpl2");
1033                                         }
1034                                         if( !arates )
1035                                         {
1036                                                 arates = strdup("Auto");
1037                                         }
1038                                         if( !dynamic_range_compression )
1039                                         {
1040                                                 dynamic_range_compression = strdup("0.0");
1041                                         }
1042                                         
1043                                 }
1044                                 
1045                                 if (!strcmp(preset_name, "AppleTV Legacy"))
1046                                 {
1047                                         if( !mux )
1048                                         {
1049                                                 mux = HB_MUX_MP4;
1050                                         }
1051                                         job->largeFileSize = 1;
1052                                         vcodec = HB_VCODEC_X264;
1053                                         job->vbitrate = 2500;
1054                                         if( !atracks )
1055                                         {
1056                                                 atracks = strdup("1,1");
1057                                         }
1058                                         if( !acodecs )
1059                                         {
1060                                                 acodecs = strdup("faac,copy:ac3");
1061                                         }
1062                                         if( !abitrates )
1063                                         {
1064                                                 abitrates = strdup("160,160");
1065                                         }
1066                                         if( !mixdowns )
1067                                         {
1068                                                 mixdowns = strdup("dpl2,auto");
1069                                         }
1070                                         if( !arates )
1071                                         {
1072                                                 arates = strdup("Auto,Auto");
1073                                         }
1074                                         if( !dynamic_range_compression )
1075                                         {
1076                                                 dynamic_range_compression = strdup("0.0,0.0");
1077                                         }
1078                                         if( !x264opts )
1079                                         {
1080                                                 x264opts = strdup("ref=1:b-pyramid=none:weightp=0:subme=5:me=umh:no-fast-pskip=1:cabac=0:weightb=0:8x8dct=0:trellis=0");
1081                                         }
1082                                         if( !anamorphic_mode )
1083                                         {
1084                                                 anamorphic_mode = 1;
1085                                         }
1086                                         job->chapter_markers = 1;
1087                                         
1088                                 }
1089                                 
1090                                 if (!strcmp(preset_name, "iPhone Legacy"))
1091                                 {
1092                                         if( !mux )
1093                                         {
1094                                                 mux = HB_MUX_MP4;
1095                                         }
1096                                         job->ipod_atom = 1;
1097                                         vcodec = HB_VCODEC_X264;
1098                                         job->vbitrate = 960;
1099                                         if( !atracks )
1100                                         {
1101                                                 atracks = strdup("1");
1102                                         }
1103                                         if( !acodecs )
1104                                         {
1105                                                 acodecs = strdup("faac");
1106                                         }
1107                                         if( !abitrates )
1108                                         {
1109                                                 abitrates = strdup("128");
1110                                         }
1111                                         if( !mixdowns )
1112                                         {
1113                                                 mixdowns = strdup("dpl2");
1114                                         }
1115                                         if( !arates )
1116                                         {
1117                                                 arates = strdup("Auto");
1118                                         }
1119                                         if( !dynamic_range_compression )
1120                                         {
1121                                                 dynamic_range_compression = strdup("0.0");
1122                                         }
1123                                         maxWidth = 480;
1124                                         if( !x264opts )
1125                                         {
1126                                                 x264opts = strdup("level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0");
1127                                         }
1128                                         job->chapter_markers = 1;
1129                                         
1130                                 }
1131                                 
1132                                 if (!strcmp(preset_name, "iPod Legacy"))
1133                                 {
1134                                         if( !mux )
1135                                         {
1136                                                 mux = HB_MUX_MP4;
1137                                         }
1138                                         job->ipod_atom = 1;
1139                                         vcodec = HB_VCODEC_X264;
1140                                         job->vbitrate = 1500;
1141                                         if( !atracks )
1142                                         {
1143                                                 atracks = strdup("1");
1144                                         }
1145                                         if( !acodecs )
1146                                         {
1147                                                 acodecs = strdup("faac");
1148                                         }
1149                                         if( !abitrates )
1150                                         {
1151                                                 abitrates = strdup("160");
1152                                         }
1153                                         if( !mixdowns )
1154                                         {
1155                                                 mixdowns = strdup("dpl2");
1156                                         }
1157                                         if( !arates )
1158                                         {
1159                                                 arates = strdup("Auto");
1160                                         }
1161                                         if( !dynamic_range_compression )
1162                                         {
1163                                                 dynamic_range_compression = strdup("0.0");
1164                                         }
1165                                         maxWidth = 640;
1166                                         if( !x264opts )
1167                                         {
1168                                                 x264opts = strdup("level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subme=6:8x8dct=0:trellis=0");
1169                                         }
1170                                         job->chapter_markers = 1;
1171                                         
1172                                 }
1173                                                 
1174             }
1175
1176                         if ( chapter_markers )
1177                         {
1178                                 job->chapter_markers = chapter_markers;
1179
1180                 if( marker_file != NULL )
1181                 {
1182                     hb_csv_file_t * file = hb_open_csv_file( marker_file );
1183                     hb_csv_cell_t * cell;
1184                     int row = 0;
1185                     int chapter = 0;
1186
1187                     fprintf( stderr, "Reading chapter markers from file %s\n", marker_file );
1188
1189                     if( file == NULL )
1190                     {
1191                          fprintf( stderr, "Cannot open chapter marker file, using defaults\n" );
1192                     }
1193                     else
1194                     {
1195                         /* Parse the cells */
1196                         while( NULL != ( cell = hb_read_next_cell( file ) ) )
1197                         {
1198                             /* We have a chapter number */
1199                             if( cell->cell_col == 0 )
1200                             {
1201                                 row = cell->cell_row;
1202                                 chapter = atoi( cell->cell_text );
1203                             }
1204
1205                             /* We have a chapter name */
1206                             if( cell->cell_col == 1 && row == cell->cell_row )
1207                             {
1208                                 /* If we have a valid chapter, copy the string an terminate it */
1209                                 if( chapter >= job->chapter_start && chapter <= job->chapter_end )
1210                                 {
1211                                     hb_chapter_t * chapter_s;
1212
1213                                     chapter_s = hb_list_item( job->title->list_chapter, chapter - 1);
1214                                     strncpy(chapter_s->title, cell->cell_text, 1023);
1215                                     chapter_s->title[1023] = '\0';
1216                                 }
1217                             }
1218
1219
1220                             hb_dispose_cell( cell );
1221                         }
1222
1223                         hb_close_csv_file( file );
1224                     }
1225                 }
1226                 else
1227                 {
1228                     /* No marker file */
1229
1230                     int number_of_chapters = hb_list_count(job->title->list_chapter);
1231                     int chapter;
1232
1233                     for(chapter = 0; chapter <= number_of_chapters - 1 ; chapter++)
1234                     {
1235                         hb_chapter_t * chapter_s;
1236                         chapter_s = hb_list_item( job->title->list_chapter, chapter);
1237                         snprintf( chapter_s->title, 1023, "Chapter %i", chapter + 1 );
1238                         chapter_s->title[1023] = '\0';
1239                     }
1240                 }
1241                         }
1242
1243             if( crop[0] >= 0 && crop[1] >= 0 &&
1244                 crop[2] >= 0 && crop[3] >= 0 )
1245             {
1246                 memcpy( job->crop, crop, 4 * sizeof( int ) );
1247             }
1248
1249             job->deinterlace = deinterlace;
1250             job->grayscale   = grayscale;
1251             
1252             /* Add selected filters */
1253             job->filters = hb_list_init();
1254             
1255             if( rotate )
1256             {
1257                 hb_filter_rotate.settings = rotate_opt;
1258                 hb_list_add( job->filters, &hb_filter_rotate);
1259             }
1260             if( detelecine )
1261             {
1262                 hb_filter_detelecine.settings = detelecine_opt;
1263                 hb_list_add( job->filters, &hb_filter_detelecine );
1264             }
1265             if( decomb )
1266             {
1267                 hb_filter_decomb.settings = decomb_opt;
1268                 hb_list_add( job->filters, &hb_filter_decomb );
1269             }
1270             if( deinterlace )
1271             {
1272                 hb_filter_deinterlace.settings = deinterlace_opt;
1273                 hb_list_add( job->filters, &hb_filter_deinterlace );
1274             }
1275             if( deblock )
1276             {
1277                 hb_filter_deblock.settings = deblock_opt;
1278                 hb_list_add( job->filters, &hb_filter_deblock );
1279             }
1280             if( denoise )
1281             {
1282                 hb_filter_denoise.settings = denoise_opt;
1283                 hb_list_add( job->filters, &hb_filter_denoise );
1284             }
1285
1286             switch( anamorphic_mode )
1287             {
1288                 case 0: // Non-anamorphic
1289                     
1290                     if (modulus)
1291                     {
1292                         job->modulus = modulus;
1293                     }
1294                     
1295                     if( width && height )
1296                     {
1297                         job->width  = width;
1298                         job->height = height;
1299                     }
1300                     else if( width )
1301                     {
1302                         job->width = width;
1303                         // do not exceed source dimensions by default
1304                         if( !maxHeight )
1305                             job->maxHeight = title->height;
1306                         hb_fix_aspect( job, HB_KEEP_WIDTH );
1307                     }
1308                     else if( height )
1309                     {
1310                         job->height = height;
1311                         // do not exceed source dimensions by default
1312                         if( !maxWidth )
1313                             job->maxWidth = title->width;
1314                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
1315                     }
1316                     else if( !width && !height )
1317                     {
1318                         /* Default to cropped width when one isn't specified
1319                          * avoids rounding to mod 16 regardless of modulus */
1320                         job->width = title->width - job->crop[2] - job->crop[3];
1321                         // do not exceed source dimensions by default
1322                         if( !maxHeight )
1323                             job->maxHeight = title->height;
1324                         hb_fix_aspect( job, HB_KEEP_WIDTH );
1325                     }
1326
1327                 break;
1328                 
1329                 case 1: // Strict anammorphic
1330                     job->anamorphic.mode = anamorphic_mode;
1331                 break;
1332                 
1333                 case 2: // Loose anamorphic
1334                     job->anamorphic.mode = 2;
1335                     
1336                     if (modulus)
1337                     {
1338                         job->modulus = modulus;
1339                     }
1340                     
1341                     if( itu_par )
1342                     {
1343                         job->anamorphic.itu_par = itu_par;
1344                     }
1345                     
1346                     if( width )
1347                     {
1348                         job->width = width;
1349                     }
1350                     else if( !width && !height )
1351                     {
1352                         /* Default to full width when one isn't specified for loose anamorphic */
1353                         job->width = title->width - job->crop[2] - job->crop[3];
1354                     }
1355                     
1356                 break;
1357                 
1358                 case 3: // Custom Anamorphic 3: Power User Jamboree 
1359                     job->anamorphic.mode = 3;
1360                     
1361                     if (modulus)
1362                     {
1363                         job->modulus = modulus;
1364                     }
1365                     
1366                     if( itu_par )
1367                     {
1368                         job->anamorphic.itu_par = itu_par;
1369                     }
1370                     
1371                     if( par_width && par_height )
1372                     {
1373                         job->anamorphic.par_width = par_width;
1374                         job->anamorphic.par_height = par_height;
1375                     }
1376                     
1377                     if( keep_display_aspect )
1378                     {
1379                         job->anamorphic.keep_display_aspect = 1;
1380                         
1381                         /* First, what *is* the display aspect? */
1382                         int cropped_width = title->width - job->crop[2] - job->crop[3];
1383                         int cropped_height = title->height - job->crop[0] - job->crop[1];
1384                         
1385                         /* XXX -- I'm assuming people want to keep the source
1386                            display AR even though they might have already
1387                            asked for ITU values instead. */
1388                         float source_display_width = (float)cropped_width *
1389                             (float)title->pixel_aspect_width / (float)title->pixel_aspect_height;
1390                         float display_aspect = source_display_width / (float)cropped_height;
1391                         /* When keeping display aspect, we have to rank some values
1392                            by priority in order to consistently handle situations
1393                            when more than one might be specified by default.
1394                            
1395                            * First off, PAR gets ignored. (err make this reality)
1396                            * Height will be respected over all other settings,
1397                            * If it isn't set, display_width will be followed.
1398                            * If it isn't set, width will be followed.          */
1399                         if( height )
1400                         {
1401                             /* We scale the display width to the new height */
1402                             display_width = (int)( (double)height * display_aspect );
1403                         }
1404                         else if( display_width )
1405                         {
1406                             /* We scale the height to the new display width */
1407                             height = (int)( (double)display_width / display_aspect );
1408                         }
1409                     }
1410                     
1411                     if( display_width )
1412                     {
1413                         /* Adjust the PAR to create the new display width
1414                            from the default job width. */
1415                         job->anamorphic.dar_width = display_width;
1416                         
1417                         job->anamorphic.dar_height = height ?
1418                                                         height :
1419                                                         title->height - job->crop[0] - job->crop[1];
1420                     }
1421                     
1422                     if( width && height )
1423                     {
1424                         /* Use these storage dimensions */
1425                         job->width  = width;
1426                         job->height = height;
1427                     }
1428                     else if( width )
1429                     {
1430                         /* Use just this storage width */
1431                         job->width = width;
1432                         job->height = title->height - job->crop[0] - job->crop[1];
1433                     }
1434                     else if( height )
1435                     {
1436                         /* Use just this storage height. */
1437                         job->height = height;
1438                         job->width = title->width - job->crop[2] - job->crop[3];
1439                     }
1440                     else if( !width && !height )
1441                     {
1442                         /* Assume source dimensions after cropping. */
1443                         job->width = title->width - job->crop[2] - job->crop[3];
1444                         job->height = title->height - job->crop[0] - job->crop[1];
1445                     }
1446                     
1447                 break;
1448             }
1449
1450             if( vquality >= 0.0 )
1451             {
1452                 job->vquality = vquality;
1453                 job->vbitrate = 0;
1454             }
1455             else if( vbitrate )
1456             {
1457                 job->vquality = -1.0;
1458                 job->vbitrate = vbitrate;
1459             }
1460             if( vcodec )
1461             {
1462                 job->vcodec = vcodec;
1463             }
1464             if( vrate )
1465             {
1466                 job->cfr = cfr;
1467                 job->vrate = 27000000;
1468                 job->vrate_base = vrate;
1469             }
1470             else if ( cfr )
1471             {
1472                 // cfr or pfr flag with no rate specified implies
1473                 // use the title rate.
1474                 job->cfr = cfr;
1475                 job->vrate = title->rate;
1476                 job->vrate_base = title->rate_base;
1477             }
1478
1479             /* Grab audio tracks */
1480             if( atracks )
1481             {
1482                 char * token = strtok(atracks, ",");
1483                 if (token == NULL)
1484                     token = optarg;
1485                 int track_start, track_end;
1486                 while( token != NULL )
1487                 {
1488                     audio = calloc(1, sizeof(*audio));
1489                     hb_audio_config_init(audio);
1490                     if (strlen(token) >= 3)
1491                     {
1492                         if (sscanf(token, "%d-%d", &track_start, &track_end) == 2)
1493                         {
1494                             int i;
1495                             for (i = track_start - 1; i < track_end; i++)
1496                             {
1497                                 if (i != track_start - 1)
1498                                 {
1499                                     audio = calloc(1, sizeof(*audio));
1500                                     hb_audio_config_init(audio);
1501                                 }
1502                                 audio->in.track = i;
1503                                 audio->out.track = num_audio_tracks++;
1504                                 hb_list_add(audios, audio);
1505                             }
1506                         }
1507                         else if( !strcasecmp(token, "none" ) )
1508                         {
1509                             audio->in.track = audio->out.track = -1;
1510                             audio->out.codec = 0;
1511                             hb_list_add(audios, audio);
1512                             break;
1513                         }
1514                         else
1515                         {
1516                             fprintf(stderr, "ERROR: Unable to parse audio input \"%s\", skipping.\n",
1517                                     token);
1518                             free(audio);
1519                         }
1520                     }
1521                     else
1522                     {
1523                         audio->in.track = atoi(token) - 1;
1524                         audio->out.track = num_audio_tracks++;
1525                         hb_list_add(audios, audio);
1526                     }
1527                     token = strtok(NULL, ",");
1528                 }
1529             }
1530
1531             /* Parse audio tracks */
1532             if( native_language && native_dub )
1533             {
1534                 if( hb_list_count( audios ) == 0 || !audio_explicit )
1535                 {
1536                     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
1537                     {
1538                         char audio_lang[4];
1539                         int track = i;
1540                         
1541                         audio = hb_list_audio_config_item( title->list_audio, i );
1542                         
1543                         strncpy( audio_lang, audio->lang.iso639_2, sizeof( audio_lang ) );
1544                         
1545                         if( strncasecmp( native_language, audio_lang, 
1546                                          sizeof( audio_lang ) ) == 0 &&
1547                             audio->lang.type != 3 && // Directors 1
1548                             audio->lang.type != 4)   // Directors 2
1549                         {
1550                             /*
1551                              * Matched an audio to our native language - use it.
1552                              * Replace any existing audio tracks that a preset may
1553                              * have put here.
1554                              */
1555                             if( hb_list_count(audios) == 0) {
1556                                 audio = calloc(1, sizeof(*audio));
1557                                 hb_audio_config_init(audio);
1558                                 audio->in.track = track;
1559                                 audio->out.track = num_audio_tracks++;
1560                                 /* Add it to our audios */
1561                                 hb_list_add(audios, audio);
1562                             } else {
1563                                 /*
1564                                  * Update the track numbers on what is already in
1565                                  * there.
1566                                  */
1567                                 for( i=0; i < hb_list_count( audios ); i++ )
1568                                 {
1569                                     audio = hb_list_item( audios, i );
1570
1571                                     audio->in.track = track;
1572                                 }
1573                             }
1574                             break;
1575                         }
1576                     }
1577                 } else {
1578                     fprintf( stderr, "Warning: Native language (dubbing) selection ignored since an audio track has already been selected\n");
1579                 }
1580             }
1581
1582             if( hb_list_count(audios) == 0 &&
1583                 hb_list_count(job->title->list_audio) > 0 )
1584             {        
1585                 /* Create a new audio track with default settings */
1586                 audio = calloc(1, sizeof(*audio));
1587                 hb_audio_config_init(audio);
1588                 /* Add it to our audios */
1589                 hb_list_add(audios, audio);
1590             }
1591
1592             tmp_num_audio_tracks = num_audio_tracks = hb_list_count(audios);
1593             for (i = 0; i < tmp_num_audio_tracks; i++)
1594             {
1595                 audio = hb_list_item(audios, 0);
1596                 if( (audio == NULL) || (audio->in.track == -1) ||
1597                     (audio->out.track == -1) || (audio->out.codec == 0) )
1598                 {
1599                     num_audio_tracks--;
1600                 }
1601                 else
1602                 {
1603                     if( hb_audio_add( job, audio ) == 0 )
1604                     {
1605                         fprintf(stderr, "ERROR: Invalid audio input track '%u', exiting.\n", 
1606                                 audio->in.track + 1 );
1607                         num_audio_tracks--;
1608                         exit(3);
1609                     }
1610                 }
1611                 hb_list_rem(audios, audio);
1612                 if( audio != NULL)
1613                     if( audio->out.name )
1614                     {
1615                         free( audio->out.name);
1616                     }
1617                     free( audio );
1618             }
1619
1620             /* Audio Codecs */
1621             i = 0;
1622             if( acodecs )
1623             {
1624                 char * token = strtok(acodecs, ",");
1625                 if( token == NULL )
1626                     token = acodecs;
1627                 while ( token != NULL )
1628                 {
1629                     if ((acodec = get_acodec_for_string(token)) == -1)
1630                     {
1631                         fprintf(stderr, "Invalid codec %s, using default for container.\n", token);
1632                         acodec = default_acodec;
1633                     }
1634                     if( i < num_audio_tracks )
1635                     {
1636                         audio = hb_list_audio_config_item(job->list_audio, i);
1637                         audio->out.codec = acodec;
1638                     }
1639                     else
1640                     {
1641                         hb_audio_config_t * last_audio = hb_list_audio_config_item( job->list_audio, i - 1 );
1642                         hb_audio_config_t audio;
1643
1644                         if( last_audio )
1645                         {
1646                             fprintf(stderr, "More audio codecs than audio tracks, copying track %i and using encoder %s\n",
1647                                     i, token);
1648                             hb_audio_config_init(&audio);
1649                             audio.in.track = last_audio->in.track;
1650                             audio.out.track = num_audio_tracks++;
1651                             audio.out.codec = acodec;
1652                             hb_audio_add(job, &audio);
1653                         }
1654                         else
1655                         {
1656                             fprintf(stderr, "Audio codecs and no valid audio tracks, skipping codec %s\n", token);
1657                         }
1658                     }
1659                     token = strtok(NULL, ",");
1660                     i++;
1661                 }
1662             }
1663             if( i < num_audio_tracks )
1664             {
1665                 /* We have fewer inputs than audio tracks, use the default codec for
1666                  * this container for the remaining tracks. Unless we only have one input
1667                  * then use that codec instead.
1668                  */
1669                 if (i != 1)
1670                     acodec = default_acodec;
1671                 for ( ; i < num_audio_tracks; i++)
1672                 {
1673                     audio = hb_list_audio_config_item(job->list_audio, i);
1674                     audio->out.codec = acodec;
1675                 }
1676             }
1677             /* Audio Codecs */
1678
1679             /* Sample Rate */
1680             i = 0;
1681             if( arates )
1682             {
1683                 char * token = strtok(arates, ",");
1684                 if (token == NULL)
1685                     token = arates;
1686                 while ( token != NULL )
1687                 {
1688                     arate = atoi(token);
1689                     audio = hb_list_audio_config_item(job->list_audio, i);
1690                     int j;
1691
1692                     for( j = 0; j < hb_audio_rates_count; j++ )
1693                     {
1694                         if( !strcmp( token, hb_audio_rates[j].string ) )
1695                         {
1696                             arate = hb_audio_rates[j].rate;
1697                             break;
1698                         }
1699                     }
1700
1701                     if( audio != NULL )
1702                     {
1703                         if ( !strcasecmp( token, "auto" ) )
1704                         {
1705                             arate = audio->in.samplerate;
1706                         }
1707                         if (!is_sample_rate_valid(arate))
1708                         {
1709                             fprintf(stderr, "Invalid sample rate %d, using input rate %d\n", arate, audio->in.samplerate);
1710                             arate = audio->in.samplerate;
1711                         }
1712                         
1713                         audio->out.samplerate = arate;
1714                         if( (++i) >= num_audio_tracks )
1715                             break;  /* We have more inputs than audio tracks, oops */
1716                     }
1717                     else 
1718                     {
1719                         fprintf(stderr, "Ignoring sample rate %d, no audio tracks\n", arate);
1720                     }
1721                     token = strtok(NULL, ",");
1722                 }
1723             }
1724             if (i < num_audio_tracks)
1725             {
1726                 /* We have fewer inputs than audio tracks, use default sample rate.
1727                  * Unless we only have one input, then use that for all tracks.
1728                  */
1729                 if (i != 1)
1730                     arate = audio->in.samplerate;
1731                 for ( ; i < num_audio_tracks; i++)
1732                 {
1733                     audio = hb_list_audio_config_item(job->list_audio, i);
1734                     audio->out.samplerate = arate;
1735                 }
1736             }
1737             /* Sample Rate */
1738             
1739             /* Audio Mixdown */
1740             i = 0;
1741             if ( mixdowns )
1742             {
1743                 char * token = strtok(mixdowns, ",");
1744                 if (token == NULL)
1745                     token = mixdowns;
1746                 while ( token != NULL )
1747                 {
1748                     mixdown = hb_mixdown_get_mixdown_from_short_name(token);
1749                     audio = hb_list_audio_config_item(job->list_audio, i);
1750                     if( audio != NULL )
1751                     {
1752                         audio->out.mixdown = mixdown;
1753                         if( (++i) >= num_audio_tracks )
1754                             break;  /* We have more inputs than audio tracks, oops */
1755                     }
1756                     else
1757                     {
1758                         fprintf(stderr, "Ignoring mixdown, no audio tracks\n");
1759                     }
1760                     token = strtok(NULL, ",");
1761                 }
1762             }
1763             if (i < num_audio_tracks)
1764             {
1765                 /* We have fewer inputs than audio tracks, use the default mixdown for the rest. Unless
1766                  * we only have one input, then use that.
1767                  */
1768                 int use_default = 0;
1769                 if (i != 1)
1770                     use_default = 1;
1771
1772                 for (; i < num_audio_tracks; i++)
1773                 {
1774                     audio = hb_list_audio_config_item(job->list_audio, i);
1775                     if (use_default)
1776                     {
1777                         // Get default for this tracks codec and layout
1778                         mixdown = hb_get_default_mixdown( audio->out.codec, audio->in.channel_layout );
1779                     }
1780                     audio->out.mixdown = mixdown;
1781                 }
1782             }
1783             /* Audio Mixdown */
1784
1785             /* Audio Bitrate */
1786             i = 0;
1787             if( abitrates )
1788             {
1789                 char * token = strtok(abitrates, ",");
1790                 if (token == NULL)
1791                     token = abitrates;
1792                 while ( token != NULL )
1793                 {
1794                     abitrate = atoi(token);
1795                     audio = hb_list_audio_config_item(job->list_audio, i);
1796
1797                     if( audio != NULL )
1798                     {
1799                         audio->out.bitrate = abitrate;
1800                         if( (++i) >= num_audio_tracks )
1801                             break;  /* We have more inputs than audio tracks, oops */
1802                     }
1803                     else 
1804                     {
1805                         fprintf(stderr, "Ignoring bitrate %d, no audio tracks\n", abitrate);
1806                     }
1807                     token = strtok(NULL, ",");
1808                 }
1809             }
1810             if (i < num_audio_tracks)
1811             {
1812                 /* We have fewer inputs than audio tracks, use the default bitrate
1813                  * for the remaining tracks. Unless we only have one input, then use
1814                  * that for all tracks.
1815                  */
1816                 int use_default = 0;
1817                 if (i != 1)
1818                     use_default = 1;
1819
1820                 for (; i < num_audio_tracks; i++)
1821                 {
1822                     audio = hb_list_audio_config_item(job->list_audio, i);
1823                     if (use_default)
1824                     {
1825                         abitrate = hb_get_default_audio_bitrate( 
1826                                         audio->out.codec, audio->out.samplerate,
1827                                         audio->out.mixdown );
1828                     }
1829                     audio->out.bitrate = abitrate;
1830                 }
1831             }
1832             /* Audio Bitrate */
1833
1834             /* Audio DRC */
1835             i = 0;
1836             if ( dynamic_range_compression )
1837             {
1838                 char * token = strtok(dynamic_range_compression, ",");
1839                 if (token == NULL)
1840                     token = dynamic_range_compression;
1841                 while ( token != NULL )
1842                 {
1843                     d_r_c = atof(token);
1844                     audio = hb_list_audio_config_item(job->list_audio, i);
1845                     if( audio != NULL )
1846                     {
1847                         audio->out.dynamic_range_compression = d_r_c;
1848                         if( (++i) >= num_audio_tracks )
1849                             break;  /* We have more inputs than audio tracks, oops */
1850                     } 
1851                     else
1852                     {
1853                         fprintf(stderr, "Ignoring drc, no audio tracks\n");
1854                     }
1855                     token = strtok(NULL, ",");
1856                 }
1857             }
1858             if (i < num_audio_tracks)
1859             {
1860                 /* We have fewer inputs than audio tracks, use no DRC for the remaining
1861                  * tracks. Unless we only have one input, then use the same DRC for all
1862                  * tracks.
1863                  */
1864                 if (i != 1)
1865                     d_r_c = 0;
1866                 for (; i < num_audio_tracks; i++)
1867                 {
1868                     audio = hb_list_audio_config_item(job->list_audio, i);
1869                     audio->out.dynamic_range_compression = d_r_c;
1870                 }
1871             }
1872             /* Audio DRC */
1873
1874             /* Audio Track Names */
1875             i = 0;
1876             if ( anames )
1877             {
1878                 char * token = strtok(anames, ",");
1879                 if (token == NULL)
1880                     token = anames;
1881                 while ( token != NULL )
1882                 {
1883                     audio = hb_list_audio_config_item(job->list_audio, i);
1884                     if( audio != NULL )
1885                     {
1886                         audio->out.name = strdup(token);
1887                         if( (++i) >= num_audio_tracks )
1888                             break;  /* We have more names than audio tracks, oops */
1889                     }
1890                     else
1891                     {
1892                         fprintf(stderr, "Ignoring aname '%s', no audio track\n",
1893                                 token);
1894                     }
1895                     token = strtok(NULL, ",");
1896                 }
1897             }
1898             if( i < num_audio_tracks && i == 1 )
1899             {
1900                 /* We have exactly one name and more than one audio track. Use the same
1901                  * name for all tracks. */
1902                 for ( ; i < num_audio_tracks; i++)
1903                 {
1904                     audio = hb_list_audio_config_item(job->list_audio, i);
1905                     audio->out.name = strdup(anames);
1906                 }
1907             }
1908             /* Audio Track Names */
1909
1910             /* Fix up passthru that needs to fallback to ac3 encode */
1911             for( i = 0; i < hb_list_count( job->list_audio ); )
1912             {
1913                 audio = hb_list_audio_config_item( job->list_audio, i );
1914                 if ( ( audio->out.codec & HB_ACODEC_AC3 ) &&
1915                      ( audio->out.codec & HB_ACODEC_PASS_FLAG ) &&
1916                     !( audio->out.codec & audio->in.codec ) )
1917                 {
1918                     // AC3 passthru not possible, fallback to AC3 encoder.
1919                     fprintf( stderr, "AC3 passthru requested and input codec is not AC3 for track %d, using AC3 encoder\n",
1920                         audio->out.track );
1921                     audio->out.codec = HB_ACODEC_AC3;
1922                     audio->out.mixdown = hb_get_default_mixdown( audio->out.codec, audio->in.channel_layout );
1923                     audio->out.bitrate = hb_get_default_audio_bitrate( audio->out.codec, audio->out.samplerate,
1924                         audio->out.mixdown );
1925                 }
1926                 // fix 'copy' to select a specific codec
1927                 if ( audio->out.codec & HB_ACODEC_PASS_FLAG )
1928                 {
1929                     audio->out.codec &= (audio->in.codec | HB_ACODEC_PASS_FLAG);
1930                     if ( !( audio->out.codec & HB_ACODEC_MASK ) )
1931                     {
1932                         // Passthru not possible, drop audio.
1933                         fprintf( stderr, "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n",
1934                             audio->out.track );
1935                         hb_audio_t * item = hb_list_item( job->list_audio, i );
1936                         hb_list_rem( job->list_audio, item );
1937                         continue;
1938                     }
1939                 }
1940                 i++;
1941             }
1942
1943             if( size )
1944             {
1945                 job->vbitrate = hb_calc_bitrate( job, size );
1946                 fprintf( stderr, "Calculated bitrate: %d kbps\n",
1947                          job->vbitrate );
1948             }
1949
1950             if( subtracks )
1951             {
1952                 char * token;
1953                 int    i;
1954                 int    burnpos = 0, defaultpos = 0;
1955
1956                 if ( subburn )
1957                     burnpos = strtol( subburn, NULL, 0 );
1958                 if ( subdefault )
1959                     defaultpos = strtol( subdefault, NULL, 0 );
1960                 for ( i = 0; subtracks[i] != NULL; i++ )
1961                 {
1962                     token = subtracks[i];
1963                     if( strcasecmp(token, "scan" ) == 0 )
1964                     {
1965                         int burn = 0, force = 0, def = 0;
1966
1967                         if ( subburn != NULL )
1968                         {
1969                             burn = ( i == 0 && subburn[0] == 0 ) ||
1970                                    ( burnpos == i+1 );
1971                         }
1972                         if ( subdefault != NULL )
1973                         {
1974                             def =  ( i == 0 && subdefault[0] == 0 ) ||
1975                                    ( defaultpos == i+1 );
1976                         }
1977                         force = test_sub_list( subforce, i+1 );
1978
1979                         if ( !burn )
1980                         {
1981                             job->select_subtitle_config.dest = PASSTHRUSUB;
1982                         }
1983                         else
1984                         {
1985                             if ( sub_burned )
1986                             {
1987                                 continue;
1988                             }
1989                             sub_burned = 1;
1990                         }
1991                         job->select_subtitle_config.force = force;
1992                         job->select_subtitle_config.default_track = def;
1993                         subtitle_scan = 1;
1994                     }
1995                     else
1996                     {
1997                         hb_subtitle_t        * subtitle;
1998                         hb_subtitle_config_t   sub_config;
1999                         int                    track;
2000                         int                    burn = 0, force = 0, def = 0;
2001
2002                         track = atoi(token) - 1;
2003                         subtitle = hb_list_item(title->list_subtitle, track);
2004                         if( subtitle == NULL ) 
2005                         {
2006                             fprintf( stderr, "Warning: Could not find subtitle track %d, skipped\n", track+1 );
2007                             continue;
2008                         }
2009                         sub_config = subtitle->config;
2010
2011                         if ( subburn != NULL )
2012                         {
2013                             burn = ( i == 0 && subburn[0] == 0 ) ||
2014                                    ( burnpos == i+1 );
2015                         }
2016                         if ( subdefault != NULL )
2017                         {
2018                             def =  ( i == 0 && subdefault[0] == 0 ) ||
2019                                    ( defaultpos == i+1 );
2020                         }
2021
2022                         force = test_sub_list(subforce, i+1);
2023                         
2024                         int supports_burn =
2025                             ( subtitle->source == VOBSUB ) ||
2026                             ( subtitle->source == SSASUB );
2027                         
2028                         if ( burn && supports_burn )
2029                         {
2030                             // Only allow one subtitle to be burned into video
2031                             if ( sub_burned )
2032                             {
2033                                 fprintf( stderr, "Warning: Skipping subtitle track %d, can't have more than one track burnt in\n", track+1 );
2034                                 continue;
2035                             }
2036                             sub_burned = 1;
2037                             
2038                             // Mark as burn-in
2039                             sub_config.dest = RENDERSUB;
2040                         }
2041                         else
2042                         {
2043                             sub_config.dest = PASSTHRUSUB;
2044                         }
2045                         sub_config.force = force;
2046                         sub_config.default_track = def;
2047                         hb_subtitle_add( job, &sub_config, track );
2048                     }
2049                 }
2050             }
2051
2052             if( srtfile )
2053             {
2054                 char * token;
2055                 int i;
2056                 hb_subtitle_config_t sub_config;
2057
2058                 for( i=0; srtfile[i] != NULL; i++ )
2059                 {
2060                     char *codeset = "L1";
2061                     int64_t offset = 0;
2062                     char *lang = "und";
2063
2064                     token = srtfile[i];
2065                     if( srtcodeset && srtcodeset[i] )
2066                     {
2067                         codeset = srtcodeset[i];
2068                     }
2069                     if( srtoffset && srtoffset[i] )
2070                     {
2071                         offset = strtoll( srtoffset[i], &srtoffset[i], 0 );
2072                     }
2073                     if ( srtlang && srtlang[i] )
2074                     {
2075                         lang = srtlang[i];
2076                     }
2077                     sub_config.default_track = 
2078                            ( srtdefault != -1 ) && ( srtdefault == i + 1 );
2079                     sub_config.force = 0;
2080                     strncpy( sub_config.src_filename, srtfile[i], 255);
2081                     sub_config.src_filename[255] = 0;
2082                     strncpy( sub_config.src_codeset, codeset, 39);
2083                     sub_config.src_codeset[39] = 0;
2084                     sub_config.offset = offset;
2085
2086                     hb_srt_add( job, &sub_config, lang);
2087                 }
2088             }
2089
2090             if( native_language )
2091             {
2092                 char audio_lang[4];
2093                 
2094                 audio = hb_list_audio_config_item(job->list_audio, 0);
2095                 
2096                 if( audio ) 
2097                 {
2098                     strncpy( audio_lang, audio->lang.iso639_2, sizeof( audio_lang ) );
2099                     
2100                     if( strncasecmp( native_language, audio_lang, 
2101                                      sizeof( audio_lang ) ) != 0 )
2102                     {
2103                         /*
2104                          * Audio language is not the same as our native language. 
2105                          * If we have any subtitles in our native language they
2106                          * should be selected here if they haven't already been.
2107                          */
2108                         hb_subtitle_t *subtitle, *subtitle2 = NULL;
2109                         int matched_track = 0;
2110
2111                         for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
2112                         {
2113                             subtitle = hb_list_item( title->list_subtitle, i );
2114                             matched_track = i;
2115                             if( strcmp( subtitle->iso639_2, native_language ) == 0 )
2116                             {  
2117                                 /*
2118                                  * Found the first matching subtitle in our
2119                                  * native language. Is it already selected?
2120                                  */
2121                                 for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
2122                                 {
2123                                     subtitle2 =  hb_list_item( job->list_subtitle, i );
2124                                     
2125                                     if( subtitle2->track == subtitle->track) {
2126                                         /*
2127                                          * Already selected
2128                                          */
2129                                         break;
2130                                     }
2131                                     subtitle2 = NULL;
2132                                 }
2133                                 
2134                                 if( subtitle2 == NULL ) 
2135                                 {
2136                                     /*
2137                                      * Not already selected, so select it.
2138                                      */
2139                                     hb_subtitle_config_t sub_config;
2140
2141                                     if( native_dub )
2142                                     {
2143                                         fprintf( stderr, "Warning: no matching audio for native language - using subtitles instead.\n");
2144                                     }
2145                                     sub_config = subtitle->config;
2146
2147                                     if( mux == HB_MUX_MKV || subtitle->format == TEXTSUB)
2148                                     {
2149                                         sub_config.dest = PASSTHRUSUB;
2150                                     }
2151
2152                                     sub_config.force = 0;
2153                                     sub_config.default_track = 1;
2154                                     hb_subtitle_add( job, &sub_config, matched_track);
2155                                 }
2156                                 /*
2157                                  * Stop searching.
2158                                  */
2159                                 break;
2160                             }
2161                         }
2162                     }
2163                 }
2164             }
2165
2166             if( job->mux )
2167             {
2168                 job->mux = mux;
2169             }
2170
2171             if ( largeFileSize )
2172             {
2173                 job->largeFileSize = 1;
2174             }
2175             if ( mp4_optimize )
2176             {
2177                 job->mp4_optimize = 1;
2178             }
2179             if ( ipod_atom )
2180             {
2181                 job->ipod_atom = 1;
2182             }
2183
2184             job->file = strdup( output );
2185
2186             if( color_matrix )
2187             {
2188                 job->color_matrix = color_matrix;
2189             }
2190
2191             if( x264opts != NULL && *x264opts != '\0' )
2192             {
2193                 job->x264opts = x264opts;
2194             }
2195             else /*avoids a bus error crash when options aren't specified*/
2196             {
2197                 job->x264opts =  NULL;
2198             }
2199             if (maxWidth)
2200                 job->maxWidth = maxWidth;
2201             if (maxHeight)
2202                 job->maxHeight = maxHeight;
2203
2204             if( start_at_preview )
2205             {
2206                 job->start_at_preview = start_at_preview - 1;
2207                 job->seek_points = preview_count;
2208             }
2209             
2210             if( stop_at_pts )
2211             {
2212                 job->pts_to_stop = stop_at_pts;
2213                 subtitle_scan = 0;
2214             }
2215             
2216             if( stop_at_frame )
2217             {
2218                 job->frame_to_stop = stop_at_frame;
2219                 subtitle_scan = 0;
2220             }
2221             
2222             if( start_at_pts )
2223             {
2224                 job->pts_to_start = start_at_pts;
2225                 subtitle_scan = 0;
2226             }
2227             
2228             if( start_at_frame )
2229             {
2230                 job->frame_to_start = start_at_frame;
2231                 subtitle_scan = 0;
2232             }
2233             
2234             if( subtitle_scan )
2235             {
2236                 char *x264opts_tmp;
2237
2238                 /*
2239                  * When subtitle scan is enabled do a fast pre-scan job
2240                  * which will determine which subtitles to enable, if any.
2241                  */
2242                 job->pass = -1;
2243
2244                 x264opts_tmp = job->x264opts;
2245
2246                 job->x264opts = NULL;
2247
2248                 job->indepth_scan = subtitle_scan;
2249                 fprintf( stderr, "Subtitle Scan Enabled - enabling "
2250                          "subtitles if found for foreign language segments\n");
2251
2252                 /*
2253                  * Add the pre-scan job
2254                  */
2255                 hb_add( h, job );
2256
2257                 job->x264opts = x264opts_tmp;
2258             }
2259
2260             if( twoPass )
2261             {
2262                 /*
2263                  * If subtitle_scan is enabled then only turn it on
2264                  * for the first pass and then off again for the
2265                  * second.
2266                  */
2267                 job->pass = 1;
2268
2269                 job->indepth_scan = 0;
2270
2271                 if (x264opts)
2272                 {
2273                     x264opts2 = strdup(x264opts);
2274                 }
2275
2276                 /*
2277                  * If turbo options have been selected then append them
2278                  * to the x264opts now (size includes one ':' and the '\0')
2279                  */
2280                 if( turbo_opts_enabled )
2281                 {
2282                     int size = (x264opts ? strlen(x264opts) : 0) + strlen(turbo_opts) + 2;
2283                     char *tmp_x264opts;
2284
2285                     tmp_x264opts = malloc(size * sizeof(char));
2286                     if( x264opts )
2287                     {
2288                         snprintf( tmp_x264opts, size, "%s:%s",
2289                                   x264opts, turbo_opts );
2290                         free( x264opts );
2291                     } else {
2292                         /*
2293                          * No x264opts to modify, but apply the turbo options
2294                          * anyway as they may be modifying defaults
2295                          */
2296                         snprintf( tmp_x264opts, size, "%s",
2297                                   turbo_opts );
2298                     }
2299                     x264opts = tmp_x264opts;
2300
2301                     fprintf( stderr, "Modified x264 options for pass 1 to append turbo options: %s\n",
2302                              x264opts );
2303
2304                     job->x264opts = x264opts;
2305                 }
2306                 hb_add( h, job );
2307
2308                 job->pass = 2;
2309                 /*
2310                  * On the second pass we turn off subtitle scan so that we
2311                  * can actually encode using any subtitles that were auto
2312                  * selected in the first pass (using the whacky select-subtitle
2313                  * attribute of the job).
2314                  */
2315                 job->indepth_scan = 0;
2316
2317                 job->x264opts = x264opts2;
2318
2319                 hb_add( h, job );
2320             }
2321             else
2322             {
2323                 /*
2324                  * Turn on subtitle scan if requested, note that this option
2325                  * precludes encoding of any actual subtitles.
2326                  */
2327
2328                 job->indepth_scan = 0;
2329                 job->pass = 0;
2330                 hb_add( h, job );
2331             }
2332             hb_start( h );
2333             break;
2334         }
2335
2336 #define p s.param.working
2337         case HB_STATE_SEARCHING:
2338             fprintf( stdout, "\rEncoding: task %d of %d, Searching for start time, %.2f %%",
2339                      p.job_cur, p.job_count, 100.0 * p.progress );
2340             if( p.seconds > -1 )
2341             {
2342                 fprintf( stdout, " (ETA %02dh%02dm%02ds)", 
2343                          p.hours, p.minutes, p.seconds );
2344             }
2345             fflush(stdout);
2346             break;
2347
2348         case HB_STATE_WORKING:
2349             fprintf( stdout, "\rEncoding: task %d of %d, %.2f %%",
2350                      p.job_cur, p.job_count, 100.0 * p.progress );
2351             if( p.seconds > -1 )
2352             {
2353                 fprintf( stdout, " (%.2f fps, avg %.2f fps, ETA "
2354                          "%02dh%02dm%02ds)", p.rate_cur, p.rate_avg,
2355                          p.hours, p.minutes, p.seconds );
2356             }
2357             fflush(stdout);
2358             break;
2359 #undef p
2360
2361 #define p s.param.muxing
2362         case HB_STATE_MUXING:
2363         {
2364             if (show_mux_warning)
2365             {
2366                 fprintf( stdout, "\rMuxing: this may take awhile..." );
2367                 fflush(stdout);
2368                 show_mux_warning = 0;
2369             }
2370             break;
2371         }
2372 #undef p
2373
2374 #define p s.param.workdone
2375         case HB_STATE_WORKDONE:
2376             /* Print error if any, then exit */
2377             switch( p.error )
2378             {
2379                 case HB_ERROR_NONE:
2380                     fprintf( stderr, "\nRip done!\n" );
2381                     break;
2382                 case HB_ERROR_CANCELED:
2383                     fprintf( stderr, "\nRip canceled.\n" );
2384                     break;
2385                 default:
2386                     fprintf( stderr, "\nRip failed (error %x).\n",
2387                              p.error );
2388             }
2389             die = 1;
2390             break;
2391 #undef p
2392     }
2393     return 0;
2394 }
2395
2396 /****************************************************************************
2397  * SigHandler:
2398  ****************************************************************************/
2399 static volatile int64_t i_die_date = 0;
2400 void SigHandler( int i_signal )
2401 {
2402     if( die == 0 )
2403     {
2404         die = 1;
2405         i_die_date = hb_get_date();
2406         fprintf( stderr, "Signal %d received, terminating - do it "
2407                  "again in case it gets stuck\n", i_signal );
2408     }
2409     else if( i_die_date + 500 < hb_get_date() )
2410     {
2411         fprintf( stderr, "Dying badly, files might remain in your /tmp\n" );
2412         exit( 1 );
2413     }
2414 }
2415
2416 /****************************************************************************
2417  * ShowHelp:
2418  ****************************************************************************/
2419 static void ShowHelp()
2420 {
2421     int i;
2422     FILE* const out = stdout;
2423
2424     fprintf( out,
2425     "Syntax: HandBrakeCLI [options] -i <device> -o <file>\n"
2426     "\n"
2427     "### General Handbrake Options------------------------------------------------\n\n"
2428     "    -h, --help              Print help\n"
2429     "    -u, --update            Check for updates and exit\n"
2430     "    -v, --verbose <#>       Be verbose (optional argument: logging level)\n"
2431     "    -C, --cpu               Set CPU count (default: autodetected)\n"
2432     "    -Z. --preset <string>   Use a built-in preset. Capitalization matters, and\n"
2433     "                            if the preset name has spaces, surround it with\n"
2434     "                            double quotation marks\n"
2435     "    -z, --preset-list       See a list of available built-in presets\n"
2436     "        --no-dvdnav         Do not use dvdnav for reading DVDs\n"
2437     "                            (experimental, enabled by default for testing)\n"
2438     "\n"
2439
2440     "### Source Options-----------------------------------------------------------\n\n"
2441     "    -i, --input <string>    Set input device\n"
2442     "    -t, --title <number>    Select a title to encode (0 to scan all titles only,\n"
2443     "                            default: 1)\n"
2444     "        --scan              Scan selected title only.\n"
2445     "        --main-feature      Detect and select the main feature title.\n"
2446     "    -c, --chapters <string> Select chapters (e.g. \"1-3\" for chapters\n"
2447     "                            1 to 3, or \"3\" for chapter 3 only,\n"
2448     "                            default: all chapters)\n"
2449     "        --angle <number>    Select the DVD angle\n"
2450     "        --previews <#:B>    Select how many preview images are generated (max 30),\n"
2451     "                            and whether or not they're stored to disk (0 or 1).\n"
2452     "                            (default: 10:0)\n"
2453     "    --start-at-preview <#>  Start encoding at a given preview.\n"
2454     "    --start-at    <unit:#>  Start encoding at a given frame, duration (in seconds),\n"
2455     "                            or pts (on a 90kHz clock)\n"
2456     "    --stop-at     <unit:#>  Stop encoding at a given frame, duration (in seconds),\n"
2457     "                            or pts (on a 90kHz clock)"
2458     "\n"
2459
2460     "### Destination Options------------------------------------------------------\n\n"
2461     "    -o, --output <string>   Set output file name\n"
2462     "    -f, --format <string>   Set output format (mp4/mkv, default:\n"
2463     "                            autodetected from file name)\n"
2464     "    -m, --markers           Add chapter markers (mp4 and mkv output formats only)\n"
2465     "    -4, --large-file        Use 64-bit mp4 files that can hold more than\n"
2466     "                            4 GB. Note: Breaks iPod, PS3 compatibility.\n"""
2467     "    -O, --optimize          Optimize mp4 files for HTTP streaming\n"
2468     "    -I, --ipod-atom         Mark mp4 files so 5.5G iPods will accept them\n"
2469     "\n"
2470
2471
2472     "### Video Options------------------------------------------------------------\n\n"
2473     "    -e, --encoder <string>  Set video library encoder (ffmpeg,x264,theora)\n"
2474     "                            (default: ffmpeg)\n"
2475     "    -x, --x264opts <string> Specify advanced x264 options in the\n"
2476     "                            same style as mencoder:\n"
2477     "                            option1=value1:option2=value2\n"
2478     "    -q, --quality <number>  Set video quality\n"
2479     "    -S, --size <MB>         Set target size\n"
2480     "    -b, --vb <kb/s>         Set video bitrate (default: 1000)\n"
2481     "    -2, --two-pass          Use two-pass mode\n"
2482     "    -T, --turbo             When using 2-pass use the turbo options\n"
2483     "                            on the first pass to improve speed\n"
2484     "                            (only works with x264, affects PSNR by about 0.05dB,\n"
2485     "                            and increases first pass speed two to four times)\n"
2486     "    -r, --rate              Set video framerate (" );
2487     for( i = 0; i < hb_video_rates_count; i++ )
2488     {
2489         fprintf( out, hb_video_rates[i].string );
2490         if( i != hb_video_rates_count - 1 )
2491             fprintf( out, "/" );
2492     }
2493     fprintf( out, ")\n"
2494     "                            Be aware that not specifying a framerate lets\n"
2495     "                            HandBrake preserve a source's time stamps,\n"
2496     "                            potentially creating variable framerate video\n"
2497     "    --vfr, --cfr, --pfr     Select variable, constant or peak-limited\n"
2498     "                            frame rate control. VFR preserves the source\n"
2499     "                            timing. CFR makes the output constant rate at\n"
2500     "                            the rate given by the -r flag (or the source's\n"
2501     "                            average rate if no -r is given). PFR doesn't\n"
2502     "                            allow the rate to go over the rate specified\n"
2503     "                            with the -r flag but won't change the source\n"
2504     "                            timing if it's below that rate.\n"
2505     "                            If none of these flags are given, the default\n"
2506     "                            is --cfr when -r is given and --vfr otherwise\n"
2507
2508     "\n"
2509     "### Audio Options-----------------------------------------------------------\n\n"
2510     "    -a, --audio <string>    Select audio track(s), separated by commas\n"
2511     "                            More than one output track can be used for one\n"
2512     "                            input.\n"
2513     "                            (\"none\" for no audio, \"1,2,3\" for multiple\n"
2514     "                             tracks, default: first one)\n" );
2515
2516 #ifdef __APPLE_CC__
2517     fprintf( out,
2518     "    -E, --aencoder <string> Audio encoder(s)\n"
2519     "                                (ca_aac/faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\n"
2520     "                            copy, copy:ac3 and copy:dts meaning passthrough.\n"
2521     "                            copy will passthrough either ac3 or dts.\n"
2522     "                            Separated by commas for more than one audio track.\n"
2523     "                            (default: ca_aac)\n" );
2524 #else
2525     fprintf( out,
2526     "    -E, --aencoder <string> Audio encoder(s):\n"
2527     "                                (faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\n"
2528     "                            copy, copy:ac3 and copy:dts meaning passthrough.\n"
2529     "                            copy will passthrough either ac3 or dts.\n"
2530     "                            Separated by commas for more than one audio track.\n"
2531     "                            (default: faac for mp4, lame for mkv)\n" );
2532 #endif
2533     fprintf( out,
2534     "    -B, --ab <kb/s>         Set audio bitrate(s) (default: depends on the\n"
2535     "                            selected codec, mixdown and samplerate)\n"
2536     "                            Separated by commas for more than one audio track.\n"
2537     "    -6, --mixdown <string>  Format(s) for surround sound downmixing\n"
2538     "                            Separated by commas for more than one audio track.\n"
2539     "                            (mono/stereo/dpl1/dpl2/6ch, default: up to 6ch for ac3,\n"
2540     "                            up to dpl2 for other encoders)\n"
2541     "    -R, --arate             Set audio samplerate(s) (" );
2542     for( i = 0; i < hb_audio_rates_count; i++ )
2543     {
2544         fprintf( out, hb_audio_rates[i].string );
2545         if( i != hb_audio_rates_count - 1 )
2546             fprintf( out, "/" );
2547     }
2548     fprintf( out, " kHz)\n"
2549     "                            Separated by commas for more than one audio track.\n"
2550     "    -D, --drc <float>       Apply extra dynamic range compression to the audio,\n"
2551     "                            making soft sounds louder. Range is 1.0 to 4.0\n"
2552     "                            (too loud), with 1.5 - 2.5 being a useful range.\n"
2553     "                            Separated by commas for more than one audio track.\n"
2554     "    -A, --aname <string>    Audio track name(s),\n"
2555     "                            Separated by commas for more than one audio track.\n"
2556     "\n"
2557
2558     "### Picture Settings---------------------------------------------------------\n\n"
2559     "    -w, --width <number>    Set picture width\n"
2560     "    -l, --height <number>   Set picture height\n"
2561     "        --crop <T:B:L:R>    Set cropping values (default: autocrop)\n"
2562     "    -Y, --maxHeight <#>     Set maximum height\n"
2563     "    -X, --maxWidth <#>      Set maximum width\n"
2564     "    --strict-anamorphic     Store pixel aspect ratio in video stream\n"
2565     "    --loose-anamorphic      Store pixel aspect ratio with specified width\n"
2566     "    --custom-anamorphic     Store pixel aspect ratio in video stream and\n"
2567     "                            directly control all parameters.\n"
2568     "    --display-width         Set the width to scale the actual pixels to\n"
2569     "      <number>              at playback, for custom anamorphic.\n"
2570     "    --keep-display-aspect   Preserve the source's display aspect ratio\n"
2571     "                            when using custom anamorphic\n"
2572     "    --pixel-aspect          Set a custom pixel aspect for custom anamorphic\n"
2573     "      <PARX:PARY>\n"
2574     "                            (--display-width and --pixel-aspect are mutually\n"
2575     "                             exclusive and the former will override the latter)\n"
2576     "    --itu-par               Use wider, ITU pixel aspect values for loose and\n"
2577     "                            custom anamorphic, useful with underscanned sources\n"
2578     "    --modulus               Set the number you want the scaled pixel dimensions\n"
2579     "      <number>              to divide cleanly by. Does not affect strict\n"
2580     "                            anamorphic mode, which is always mod 2 (default: 16)\n"
2581     "    -M  --color-matrix      Set the color space signaled by the output\n"
2582     "          <601 or 709>      (Bt.601 is mostly for SD content, Bt.709 for HD,\n"
2583     "                             default: set by resolution)\n"
2584     "\n"
2585
2586     "### Filters---------------------------------------------------------\n\n"
2587
2588      "    -d, --deinterlace       Deinterlace video with yadif/mcdeint filter\n"
2589      "          <YM:FD:MM:QP>     (default 0:-1:-1:1)\n"
2590      "           or\n"
2591      "          <fast/slow/slower>\n"
2592      "    -5, --decomb            Selectively deinterlaces when it detects combing\n"
2593      "          <MO:ME:MT:ST:BT:BX:BY:MG:VA:LA:DI:ER:NO:MD:PP:FD>\n"
2594      "          (default: 7:2:6:9:80:16:16:10:20:20:4:2:50:24:1:-1)\n"
2595      "    -9, --detelecine        Detelecine (ivtc) video with pullup filter\n"
2596      "                            Note: this filter drops duplicate frames to\n"
2597      "                            restore the pre-telecine framerate, unless you\n"
2598      "                            specify a constant framerate (--rate 29.97)\n"
2599      "          <L:R:T:B:SB:MP:FD>   (default 1:1:4:4:0:0:-1)\n"
2600      "    -8, --denoise           Denoise video with hqdn3d filter\n"
2601      "          <SL:SC:TL:TC>     (default 4:3:6:4.5)\n"
2602      "           or\n"
2603      "          <weak/medium/strong>\n"
2604      "    -7, --deblock           Deblock video with pp7 filter\n"
2605      "          <QP:M>            (default 5:2)\n"
2606      "        --rotate            Flips images axes\n"
2607      "          <M>               (default 3)\n"
2608     "    -g, --grayscale         Grayscale encoding\n"
2609     "\n"
2610
2611     "### Subtitle Options------------------------------------------------------------\n\n"
2612     "    -s, --subtitle <string> Select subtitle track(s), separated by commas\n"
2613     "                            More than one output track can be used for one\n"
2614     "                            input.\n"
2615     "                            Example: \"1,2,3\" for multiple tracks.\n"
2616     "                            A special track name \"scan\" adds an extra 1st pass.\n"
2617     "                            This extra pass scans subtitles matching the\n"
2618     "                            language of the first audio or the language \n"
2619     "                            selected by --native-language.\n"
2620     "                            The one that's only used 10 percent of the time\n"
2621     "                            or less is selected. This should locate subtitles\n"
2622     "                            for short foreign language segments. Best used in\n"
2623     "                            conjunction with --subtitle-forced.\n"
2624     "    -F, --subtitle-forced   Only display subtitles from the selected stream if\n"
2625     "          <string>          the subtitle has the forced flag set. The values in\n"
2626     "                            \"string\" are indexes into the subtitle list\n"
2627     "                            specified with '--subtitle'.\n"
2628     "                            Separated by commas for more than one audio track.\n"
2629     "                            Example: \"1,2,3\" for multiple tracks.\n"
2630     "                            If \"string\" is omitted, the first track is forced.\n"
2631     "        --subtitle-burn     \"Burn\" the selected subtitle into the video track\n"
2632     "          <number>          If \"number\" is omitted, the first track is burned.\n"
2633     "                            \"number\" is an index into the subtitle list\n"
2634     "                            specified with '--subtitle'.\n"
2635     "        --subtitle-default  Flag the selected subtitle as the default subtitle\n"
2636     "          <number>          to be displayed upon playback.  Setting no default\n"
2637     "                            means no subtitle will be automatically displayed\n"
2638     "                            If \"number\" is omitted, the first track is default.\n"
2639     "                            \"number\" is an index into the subtitle list\n"
2640     "                            specified with '--subtitle'.\n"
2641     "    -N, --native-language   Specifiy the your language preference. When the first\n"
2642     "          <string>          audio track does not match your native language then\n"
2643     "                            select the first subtitle that does. When used in\n"
2644     "                            conjunction with --native-dub the audio track is\n"
2645     "                            changed in preference to subtitles. Provide the\n"
2646     "                            language's iso639-2 code (fre, eng, spa, dut, et cetera)\n"
2647     "        --native-dub        Used in conjunction with --native-language\n"
2648     "                            requests that if no audio tracks are selected the\n"
2649     "                            default selected audio track will be the first one\n"
2650     "                            that matches the --native-language. If there are no\n"
2651     "                            matching audio tracks then the first matching\n"
2652     "                            subtitle track is used instead.\n"
2653     "        --srt-file <string> SubRip SRT filename(s), separated by commas.\n"
2654     "        --srt-codeset       Character codeset(s) that the SRT file(s) are\n"
2655     "          <string>          encoded in, separted by commas.\n"
2656     "                            Use 'iconv -l' for a list of valid\n"
2657     "                            codesets. If not specified latin1 is assumed\n"
2658     "        --srt-offset        Offset in milli-seconds to apply to the SRT file(s)\n"
2659     "          <string>          separted by commas. If not specified zero is assumed.\n"
2660     "                            Offsets may be negative.\n"
2661     "        --srt-lang <string> Language as an iso639-2 code fra, eng, spa et cetera)\n"
2662     "                            for the SRT file(s) separated by commas. If not specified\n"
2663     "                            then 'und' is used.\n"
2664     "        --srt-default       Flag the selected srt as the default subtitle\n"
2665     "          <number>          to be displayed upon playback.  Setting no default\n"
2666     "                            means no subtitle will be automatically displayed\n"
2667     "                            If \"number\" is omitted, the first srt is default.\n"
2668     "                            \"number\" is an 1 based index into the srt-file list\n"
2669     "\n"
2670
2671
2672     );
2673 }
2674
2675 /****************************************************************************
2676  * ShowPresets:
2677  ****************************************************************************/
2678 static void ShowPresets()
2679 {
2680         fprintf( stderr, "%s - %s - %s\n", HB_PROJECT_TITLE, HB_PROJECT_BUILD_TITLE, HB_PROJECT_URL_WEBSITE );
2681         
2682         printf("\n< Apple\n");
2683         
2684     printf("\n   + Universal:  -e x264  -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -X 720 --loose-anamorphic -m -x cabac=0:ref=2:me=umh:bframes=0:weightp=0:8x8dct=0:trellis=0:subme=6\n");
2685         
2686     printf("\n   + iPod:  -e x264  -b 700 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 320 -m -x level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:subme=6:8x8dct=0:trellis=0\n");
2687         
2688     printf("\n   + iPhone & iPod Touch:  -e x264  -q 20.0 -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 -f mp4 -X 480 -m -x cabac=0:ref=2:me=umh:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0\n");
2689         
2690     printf("\n   + iPhone 4:  -e x264  -q 20.0 -r 29.97 --pfr  -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -4 -X 960 --loose-anamorphic -m\n");
2691         
2692     printf("\n   + iPad:  -e x264  -q 20.0 -r 29.97 --pfr  -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -4 -X 1024 --loose-anamorphic -m\n");
2693         
2694     printf("\n   + AppleTV:  -e x264  -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 -X 960 --loose-anamorphic -m -x cabac=0:ref=2:me=umh:b-pyramid=none:b-adapt=2:weightb=0:trellis=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500\n");
2695         
2696     printf("\n   + AppleTV 2:  -e x264  -q 20.0 -r 29.97 --pfr  -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 -X 1280 --loose-anamorphic -m\n");
2697         
2698     printf("\n>\n");
2699         
2700     printf("\n< Regular\n");
2701         
2702     printf("\n   + Normal:  -e x264  -q 20.0 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 --strict-anamorphic -m -x ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0\n");
2703         
2704     printf("\n   + High Profile:  -e x264  -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 --detelecine --decomb --loose-anamorphic -m -x b-adapt=2:rc-lookahead=50\n");
2705         
2706     printf("\n>\n");
2707         
2708     printf("\n< Legacy\n");
2709         
2710     printf("\n   + Classic:  -b 1000 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4\n");
2711         
2712     printf("\n   + AppleTV Legacy:  -e x264  -b 2500 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 --strict-anamorphic -m -x ref=1:b-pyramid=none:weightp=0:subme=5:me=umh:no-fast-pskip=1:cabac=0:weightb=0:8x8dct=0:trellis=0\n");
2713         
2714     printf("\n   + iPhone Legacy:  -e x264  -b 960 -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 480 -m -x level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0\n");
2715         
2716     printf("\n   + iPod Legacy:  -e x264  -b 1500 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 640 -m -x level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subme=6:8x8dct=0:trellis=0\n");
2717         
2718     printf("\n>\n");
2719
2720 }
2721
2722 static char * hb_strndup( char * str, int len )
2723 {
2724         char * res;
2725         int str_len = strlen( str );
2726
2727         res = malloc( len > str_len ? str_len + 1 : len + 1 );
2728         strncpy( res, str, len );
2729         res[len] = '\0';
2730         return res;
2731 }
2732
2733 static char** str_split( char *str, char delem )
2734 {
2735     char *  pos;
2736     char *  end;
2737     char ** ret;
2738     int     count, i;
2739
2740     if ( str == NULL || str[0] == 0 )
2741     {
2742         ret = malloc( sizeof(char*) );
2743         *ret = NULL;
2744         return ret;
2745     }
2746
2747     // Find number of elements in the string
2748     count = 1;
2749     pos = str;
2750     while ( ( pos = strchr( pos, delem ) ) != NULL )
2751     {
2752         count++;
2753         pos++;
2754     }
2755
2756     ret = calloc( ( count + 1 ), sizeof(char*) );
2757
2758     pos = str;
2759     for ( i = 0; i < count - 1; i++ )
2760     {
2761         end = strchr( pos, delem );
2762         ret[i] = hb_strndup(pos, end - pos);
2763         pos = end + 1;
2764     }
2765     ret[i] = strdup(pos);
2766
2767     return ret;
2768 }
2769
2770 /****************************************************************************
2771  * ParseOptions:
2772  ****************************************************************************/
2773 static int ParseOptions( int argc, char ** argv )
2774 {
2775     
2776     #define PREVIEWS            257
2777     #define START_AT_PREVIEW    258
2778     #define START_AT            259
2779     #define STOP_AT             260
2780     #define ANGLE               261
2781     #define DVDNAV              262
2782     #define DISPLAY_WIDTH       263
2783     #define PIXEL_ASPECT        264
2784     #define MODULUS             265
2785     #define KEEP_DISPLAY_ASPECT 266
2786     #define SUB_BURNED          267
2787     #define SUB_DEFAULT         268
2788     #define NATIVE_DUB          269
2789     #define SRT_FILE            270
2790     #define SRT_CODESET         271
2791     #define SRT_OFFSET          272
2792     #define SRT_LANG            273
2793     #define SRT_DEFAULT         274
2794     #define ROTATE_FILTER       275
2795     #define SCAN_ONLY           276
2796     #define MAIN_FEATURE        277
2797     #define MIN_DURATION        278
2798     
2799     for( ;; )
2800     {
2801         static struct option long_options[] =
2802           {
2803             { "help",        no_argument,       NULL,    'h' },
2804             { "update",      no_argument,       NULL,    'u' },
2805             { "verbose",     optional_argument, NULL,    'v' },
2806             { "cpu",         required_argument, NULL,    'C' },
2807             { "no-dvdnav",      no_argument,       NULL,    DVDNAV },
2808
2809             { "format",      required_argument, NULL,    'f' },
2810             { "input",       required_argument, NULL,    'i' },
2811             { "output",      required_argument, NULL,    'o' },
2812             { "large-file",  no_argument,       NULL,    '4' },
2813             { "optimize",    no_argument,       NULL,    'O' },
2814             { "ipod-atom",   no_argument,       NULL,    'I' },
2815
2816             { "title",       required_argument, NULL,    't' },
2817             { "min-duration",required_argument, NULL,    MIN_DURATION },
2818             { "scan",        no_argument,       NULL,    SCAN_ONLY },
2819             { "main-feature",no_argument,       NULL,    MAIN_FEATURE },
2820             { "chapters",    required_argument, NULL,    'c' },
2821             { "angle",       required_argument, NULL,    ANGLE },
2822             { "markers",     optional_argument, NULL,    'm' },
2823             { "audio",       required_argument, NULL,    'a' },
2824             { "mixdown",     required_argument, NULL,    '6' },
2825             { "drc",         required_argument, NULL,    'D' },
2826             { "subtitle",    required_argument, NULL,    's' },
2827             { "subtitle-forced", optional_argument,   NULL,    'F' },
2828             { "subtitle-burned", optional_argument,   NULL,    SUB_BURNED },
2829             { "subtitle-default", optional_argument,   NULL,    SUB_DEFAULT },
2830             { "srt-file",    required_argument, NULL, SRT_FILE },
2831             { "srt-codeset", required_argument, NULL, SRT_CODESET },
2832             { "srt-offset",  required_argument, NULL, SRT_OFFSET },
2833             { "srt-lang",    required_argument, NULL, SRT_LANG },
2834             { "srt-default",    optional_argument, NULL, SRT_DEFAULT },
2835             { "native-language", required_argument, NULL,'N' },
2836             { "native-dub",  no_argument,       NULL,    NATIVE_DUB },
2837             { "encoder",     required_argument, NULL,    'e' },
2838             { "aencoder",    required_argument, NULL,    'E' },
2839             { "two-pass",    no_argument,       NULL,    '2' },
2840             { "deinterlace", optional_argument, NULL,    'd' },
2841             { "deblock",     optional_argument, NULL,    '7' },
2842             { "denoise",     optional_argument, NULL,    '8' },
2843             { "detelecine",  optional_argument, NULL,    '9' },
2844             { "decomb",      optional_argument, NULL,    '5' },
2845             { "grayscale",   no_argument,       NULL,    'g' },
2846             { "rotate",      optional_argument, NULL,   ROTATE_FILTER },
2847             { "strict-anamorphic",  no_argument, &anamorphic_mode, 1 },
2848             { "loose-anamorphic", no_argument, &anamorphic_mode, 2 },
2849             { "custom-anamorphic", no_argument, &anamorphic_mode, 3 },
2850             { "display-width", required_argument, NULL, DISPLAY_WIDTH },
2851             { "keep-display-aspect", no_argument, &keep_display_aspect, 1 },
2852             { "pixel-aspect", required_argument, NULL, PIXEL_ASPECT },
2853             { "modulus",     required_argument, NULL, MODULUS },
2854             { "itu-par",     no_argument,       &itu_par, 1  },
2855             { "width",       required_argument, NULL,    'w' },
2856             { "height",      required_argument, NULL,    'l' },
2857             { "crop",        required_argument, NULL,    'n' },
2858
2859             { "vb",          required_argument, NULL,    'b' },
2860             { "quality",     required_argument, NULL,    'q' },
2861             { "size",        required_argument, NULL,    'S' },
2862             { "ab",          required_argument, NULL,    'B' },
2863             { "rate",        required_argument, NULL,    'r' },
2864             { "arate",       required_argument, NULL,    'R' },
2865             { "x264opts",    required_argument, NULL,    'x' },
2866             { "turbo",       no_argument,       NULL,    'T' },
2867             { "maxHeight",   required_argument, NULL,    'Y' },
2868             { "maxWidth",    required_argument, NULL,    'X' },
2869             { "preset",      required_argument, NULL,    'Z' },
2870             { "preset-list", no_argument,       NULL,    'z' },
2871
2872             { "aname",       required_argument, NULL,    'A' },
2873             { "color-matrix",required_argument, NULL,    'M' },
2874             { "previews",    required_argument, NULL,    PREVIEWS },
2875             { "start-at-preview", required_argument, NULL, START_AT_PREVIEW },
2876             { "start-at",    required_argument, NULL,    START_AT },
2877             { "stop-at",    required_argument, NULL,     STOP_AT },
2878             { "vfr",         no_argument,       &cfr,    0 },
2879             { "cfr",         no_argument,       &cfr,    1 },
2880             { "pfr",         no_argument,       &cfr,    2 },
2881 #if defined( __APPLE_CC__ )
2882             { "no-vlc-dylib-path", no_argument, &no_vlc_dylib,    1 },
2883 #endif
2884             { 0, 0, 0, 0 }
2885           };
2886
2887         int option_index = 0;
2888         int c;
2889         int cur_optind;
2890
2891         cur_optind = optind;
2892         c = getopt_long( argc, argv,
2893                          "hv::uC:f:4i:Io:t:c:m::M:a:A:6:s:UF::N:e:E:"
2894                          "2dD:7895gOw:l:n:b:q:S:B:r:R:x:TY:X:Z:z",
2895                          long_options, &option_index );
2896         if( c < 0 )
2897         {
2898             break;
2899         }
2900
2901         switch( c )
2902         {
2903             case 0:
2904                 /* option was handled entirely in getopt_long */
2905                 break;
2906             case 'h':
2907                 ShowHelp();
2908                 exit( 0 );
2909             case 'u':
2910                 update = 1;
2911                 break;
2912             case 'v':
2913                 if( optarg != NULL )
2914                 {
2915                     debug = atoi( optarg );
2916                 }
2917                 else
2918                 {
2919                     debug = 1;
2920                 }
2921                 break;
2922             case 'C':
2923                 cpu = atoi( optarg );
2924                 break;
2925
2926             case 'Z':
2927                 preset = 1;
2928                 preset_name = strdup(optarg);
2929                 break;
2930             case 'z':
2931                 ShowPresets();
2932                 exit ( 0 );
2933             case DVDNAV:
2934                 dvdnav = 0;
2935                 break;
2936
2937             case 'f':
2938                 format = strdup( optarg );
2939                 break;
2940             case 'i':
2941                 input = strdup( optarg );
2942 #ifdef __APPLE_CC__
2943                 char *devName = bsd_name_for_path( input ); // alloc
2944                 if( devName )
2945                 {
2946                     if( device_is_dvd( devName ))
2947                     {
2948                         free( input );
2949                         input = malloc( strlen( "/dev/" ) + strlen( devName ) + 1 );
2950                         sprintf( input, "/dev/%s", devName );
2951                     }
2952                     free( devName );
2953                 }
2954 #endif
2955                 break;
2956             case 'o':
2957                 output = strdup( optarg );
2958                 break;
2959             case '4':
2960                 largeFileSize = 1;
2961                 break;
2962             case 'O':
2963                 mp4_optimize = 1;
2964                 break;
2965             case 'I':
2966                 ipod_atom = 1;
2967                 break;
2968
2969             case 't':
2970                 titleindex = atoi( optarg );
2971                 break;
2972             case SCAN_ONLY:
2973                 titlescan = 1;
2974                 break;
2975             case MAIN_FEATURE:
2976                 main_feature = 1;
2977                 break;
2978             case 'c':
2979             {
2980                 int start, end;
2981                 if( sscanf( optarg, "%d-%d", &start, &end ) == 2 )
2982                 {
2983                     chapter_start = start;
2984                     chapter_end   = end;
2985                 }
2986                 else if( sscanf( optarg, "%d", &start ) == 1 )
2987                 {
2988                     chapter_start = start;
2989                     chapter_end   = chapter_start;
2990                 }
2991                 else
2992                 {
2993                     fprintf( stderr, "chapters: invalid syntax (%s)\n",
2994                              optarg );
2995                     return -1;
2996                 }
2997                 break;
2998             }
2999             case ANGLE:
3000                 angle = atoi( optarg );
3001                 break;
3002             case 'm':
3003                 if( optarg != NULL )
3004                 {
3005                     marker_file = strdup( optarg );
3006                 }
3007                 chapter_markers = 1;
3008                 break;
3009             case 'a':
3010                 if( optarg != NULL )
3011                 {
3012                     atracks = strdup( optarg );
3013                     audio_explicit = 1;
3014                 }
3015                 else
3016                 {
3017                     atracks = "1" ;
3018                 }
3019                 break;
3020             case '6':
3021                 if( optarg != NULL )
3022                 {
3023                     mixdowns = strdup( optarg );
3024                 }
3025                 break;
3026             case 'D':
3027                 if( optarg != NULL )
3028                 {
3029                     dynamic_range_compression = strdup( optarg );
3030                 }
3031                 break;
3032             case 's':
3033                 subtracks = str_split( optarg, ',' );
3034                 break;
3035             case 'F':
3036                 subforce = str_split( optarg, ',' );
3037                 break;
3038             case SUB_BURNED:
3039                 if( optarg != NULL )
3040                 {
3041                     subburn = strdup( optarg );
3042                 }
3043                 else
3044                 {
3045                     subburn = "" ;
3046                 }
3047                 break;
3048             case SUB_DEFAULT:
3049                 if( optarg != NULL )
3050                 {
3051                     subdefault = strdup( optarg );
3052                 }
3053                 else
3054                 {
3055                     subdefault = "" ;
3056                 }
3057                 break;
3058             case 'N':
3059                 native_language = strdup( optarg );
3060                 break;
3061             case NATIVE_DUB:
3062                 native_dub = 1;
3063                 break;
3064             case SRT_FILE:
3065                 srtfile = str_split( optarg, ',' );
3066                 break;
3067             case SRT_CODESET:
3068                 srtcodeset = str_split( optarg, ',' );
3069                 break;
3070             case SRT_OFFSET:
3071                 srtoffset = str_split( optarg, ',' );
3072                 break;
3073             case SRT_LANG:
3074                 srtlang = str_split( optarg, ',' );
3075                 break;
3076             case SRT_DEFAULT:
3077                 if( optarg != NULL )
3078                 {
3079                     srtdefault = atoi( optarg );
3080                 }
3081                 else
3082                 {
3083                     srtdefault = 1 ;
3084                 }
3085                 break;
3086             case '2':
3087                 twoPass = 1;
3088                 break;
3089             case 'd':
3090                 if( optarg != NULL )
3091                 {
3092                     if (!( strcmp( optarg, "fast" ) ))
3093                     {
3094                         deinterlace_opt = "-1";
3095                     }
3096                     else if (!( strcmp( optarg, "slow" ) ))
3097                     {
3098                         deinterlace_opt = "2";
3099                     }
3100                     else if (!( strcmp( optarg, "slower" ) ))
3101                     {
3102                         deinterlace_opt = "0";
3103                     }
3104                     else
3105                     {
3106                         deinterlace_opt = strdup( optarg );
3107                     }
3108                 }
3109                 deinterlace = 1;
3110                 break;
3111             case '7':
3112                 if( optarg != NULL )
3113                 {
3114                     deblock_opt = strdup( optarg );
3115                 }
3116                 deblock = 1;
3117                 break;
3118             case '8':
3119                 if( optarg != NULL )
3120                 {
3121                     if (!( strcmp( optarg, "weak" ) ))
3122                     {
3123                         denoise_opt = "2:1:2:3";
3124                     }
3125                     else if (!( strcmp( optarg, "medium" ) ))
3126                     {
3127                         denoise_opt = "3:2:2:3";
3128                     }
3129                     else if (!( strcmp( optarg, "strong" ) ))
3130                     {
3131                         denoise_opt = "7:7:5:5";
3132                     }
3133                     else
3134                     {
3135                         denoise_opt = strdup( optarg );
3136                     }
3137                 }
3138                 denoise = 1;
3139                 break;
3140             case '9':
3141                 if( optarg != NULL )
3142                 {
3143                     detelecine_opt = strdup( optarg );
3144                 }
3145                 detelecine = 1;
3146                 break;
3147             case '5':
3148                 if( optarg != NULL )
3149                 {
3150                     decomb_opt = strdup( optarg );
3151                 }
3152                 decomb = 1;
3153                 break;
3154             case 'g':
3155                 grayscale = 1;
3156                 break;
3157             case ROTATE_FILTER:
3158                 if( optarg != NULL )
3159                 {
3160                     rotate_opt = strdup( optarg );
3161                 }
3162                 rotate = 1;
3163                 break;
3164             case DISPLAY_WIDTH:
3165                 if( optarg != NULL )
3166                 {
3167                     sscanf( optarg, "%i", &display_width );
3168                 }
3169                 break;
3170             case PIXEL_ASPECT:
3171                 if( optarg != NULL )
3172                 {
3173                     sscanf( optarg, "%i:%i", &par_width, &par_height );
3174                 }
3175                 break;
3176             case MODULUS:
3177                 if( optarg != NULL )
3178                 {
3179                     sscanf( optarg, "%i", &modulus );
3180                 }
3181                 break;
3182             case 'e':
3183                 if( !strcasecmp( optarg, "ffmpeg" ) )
3184                 {
3185                     vcodec = HB_VCODEC_FFMPEG;
3186                 }
3187                 else if( !strcasecmp( optarg, "x264" ) )
3188                 {
3189                     vcodec = HB_VCODEC_X264;
3190                 }
3191                 else if( !strcasecmp( optarg, "theora" ) )
3192                 {
3193                     vcodec = HB_VCODEC_THEORA;
3194                 }
3195                 else
3196                 {
3197                     fprintf( stderr, "invalid codec (%s)\n", optarg );
3198                     return -1;
3199                 }
3200                 break;
3201             case 'E':
3202                 if( optarg != NULL )
3203                 {
3204                     acodecs = strdup( optarg );
3205                 }
3206                 break;
3207             case 'w':
3208                 width = atoi( optarg );
3209                 break;
3210             case 'l':
3211                 height = atoi( optarg );
3212                 break;
3213             case 'n':
3214             {
3215                 int    i;
3216                 char * tmp = optarg;
3217                 for( i = 0; i < 4; i++ )
3218                 {
3219                     if( !*tmp )
3220                         break;
3221                     crop[i] = strtol( tmp, &tmp, 0 );
3222                     tmp++;
3223                 }
3224                 break;
3225             }
3226             case 'r':
3227             {
3228                 int i;
3229                 vrate = 0;
3230                 for( i = 0; i < hb_video_rates_count; i++ )
3231                 {
3232                     if( !strcmp( optarg, hb_video_rates[i].string ) )
3233                     {
3234                         vrate = hb_video_rates[i].rate;
3235                         break;
3236                     }
3237                 }
3238                 if( !vrate )
3239                 {
3240                     fprintf( stderr, "invalid framerate %s\n", optarg );
3241                 }
3242                 else if ( cfr == 0 )
3243                 {
3244                     cfr = 1;
3245                 }
3246                 break;
3247             }
3248             case 'R':
3249                 if( optarg != NULL )
3250                 {
3251                     arates = strdup( optarg );
3252                 }
3253                 break;
3254             case 'b':
3255                 vbitrate = atoi( optarg );
3256                 break;
3257             case 'q':
3258                 vquality = atof( optarg );
3259                 break;
3260             case 'S':
3261                 size = atoi( optarg );
3262                 break;
3263             case 'B':
3264                 if( optarg != NULL )
3265                 {
3266                     abitrates = strdup( optarg );
3267                 }
3268                 break;
3269             case 'x':
3270                 x264opts = strdup( optarg );
3271                 break;
3272             case 'T':
3273                 turbo_opts_enabled = 1;
3274                 break;
3275             case 'Y':
3276                 maxHeight = atoi( optarg );
3277                 break;
3278             case 'X':
3279                 maxWidth = atoi (optarg );
3280                 break;
3281             case 'A':
3282                 if( optarg != NULL )
3283                 {
3284                     anames = strdup( optarg );
3285                 }
3286                 break;
3287             case PREVIEWS:
3288                 sscanf( optarg, "%i:%i", &preview_count, &store_previews );
3289                 break;
3290             case START_AT_PREVIEW:
3291                 start_at_preview = atoi( optarg );
3292                 break;
3293             case START_AT:
3294                 start_at_string = strdup( optarg );
3295                 start_at_token = strtok( start_at_string, ":");
3296                 if( !strcmp( start_at_token, "frame" ) )
3297                 {
3298                     start_at_token = strtok( NULL, ":");
3299                     start_at_frame = atoi(start_at_token);
3300                 }
3301                 else if( !strcmp( start_at_token, "pts" ) )
3302                 {
3303                     start_at_token = strtok( NULL, ":");
3304                     sscanf( start_at_token, "%"SCNd64, &start_at_pts );
3305                 }
3306                 else if( !strcmp( start_at_token, "duration" ) )
3307                 {
3308                     start_at_token = strtok( NULL, ":");
3309                     sscanf( start_at_token, "%"SCNd64, &start_at_pts );
3310                     start_at_pts *= 90000LL;
3311                 }
3312                 break;
3313             case STOP_AT:
3314                 stop_at_string = strdup( optarg );
3315                 stop_at_token = strtok( stop_at_string, ":");
3316                 if( !strcmp( stop_at_token, "frame" ) )
3317                 {
3318                     stop_at_token = strtok( NULL, ":");
3319                     stop_at_frame = atoi(stop_at_token);
3320                 }
3321                 else if( !strcmp( stop_at_token, "pts" ) )
3322                 {
3323                     stop_at_token = strtok( NULL, ":");
3324                     sscanf( stop_at_token, "%"SCNd64, &stop_at_pts );
3325                 }
3326                 else if( !strcmp( stop_at_token, "duration" ) )
3327                 {
3328                     stop_at_token = strtok( NULL, ":");
3329                     sscanf( stop_at_token, "%"SCNd64, &stop_at_pts );
3330                     stop_at_pts *= 90000LL;
3331                 }
3332                 break;
3333             case 'M':
3334                 if( atoi( optarg ) == 601 )
3335                     color_matrix = 1;
3336                 else if( atoi( optarg ) == 709 )
3337                     color_matrix = 2;
3338                 break;
3339             case MIN_DURATION:
3340                 min_title_duration = strtol( optarg, NULL, 0 );
3341                 break;
3342             default:
3343                 fprintf( stderr, "unknown option (%s)\n", argv[cur_optind] );
3344                 return -1;
3345         }
3346     }
3347
3348     return 0;
3349 }
3350
3351 char * str_printf(const char *fmt, ...)
3352 {
3353     /* Guess we need no more than 100 bytes. */
3354     int len;
3355     va_list ap;
3356     int size = 100;
3357     char *tmp, *str = NULL;
3358
3359     str = (char*)malloc(size);
3360     while (1) 
3361     {
3362         /* Try to print in the allocated space. */
3363         va_start(ap, fmt);
3364         len = vsnprintf(str, size, fmt, ap);
3365         va_end(ap);
3366
3367         /* If that worked, return the string. */
3368         if (len > -1 && len < size) {
3369             return str;
3370         }
3371
3372         /* Else try again with more space. */
3373         if (len > -1)    /* glibc 2.1 */
3374             size = len+1; /* precisely what is needed */
3375         else           /* glibc 2.0 */
3376             size *= 2;  /* twice the old size */
3377
3378         tmp = (char*)realloc(str, size);
3379         if (tmp == NULL) {
3380             return str;
3381         }
3382         str = tmp;
3383     }
3384 }
3385
3386 static int CheckOptions( int argc, char ** argv )
3387 {
3388 #if defined( __APPLE_CC__ )
3389     // If OSX, add VLC dylib path and exec to make it stick.
3390     char *dylib_path;
3391
3392     if ( !no_vlc_dylib )
3393     {
3394         dylib_path = getenv("DYLD_FALLBACK_LIBRARY_PATH");
3395         if ( dylib_path == NULL ||
3396              strstr( dylib_path, "/Applications/VLC.app/Contents/MacOS/lib" ) == NULL )
3397         {
3398             char *path = NULL;
3399             char *home;
3400             int result = -1;
3401
3402             home = getenv("HOME");
3403
3404             if ( dylib_path == NULL )
3405             {
3406                 // Set the system default of $HOME/lib:/usr/local/lib:/usr/lib
3407                 // And add our extra path
3408                 if ( home != NULL )
3409                 {
3410                     path = str_printf("%s/lib:%s:%s:%s%s", home, 
3411                                       DEFAULT_DYLD_PATH, 
3412                                       EXTRA_VLC_DYLD_PATH, 
3413                                       home, EXTRA_VLC_DYLD_PATH);
3414                 }
3415                 else
3416                 {
3417                     path = str_printf("%s:%s", DEFAULT_DYLD_PATH, EXTRA_VLC_DYLD_PATH);
3418                 }
3419                 if ( path != NULL )
3420                     result = setenv("DYLD_FALLBACK_LIBRARY_PATH", path, 1);
3421             }
3422             else
3423             {
3424                 // add our extra path
3425                 if ( home != NULL )
3426                 {
3427                     path = str_printf("%s:%s:%s%s", dylib_path, EXTRA_VLC_DYLD_PATH,
3428                                                         home, EXTRA_VLC_DYLD_PATH);
3429                 }
3430                 else
3431                 {
3432                     path = str_printf("%s:%s", dylib_path, EXTRA_VLC_DYLD_PATH);
3433                 }
3434                 if ( path != NULL )
3435                     result = setenv("DYLD_FALLBACK_LIBRARY_PATH", path, 1);
3436             }
3437             if ( result == 0 )
3438             {
3439                 const char ** new_argv;
3440                 int i;
3441
3442                 new_argv = (const char**)malloc( (argc + 2) * sizeof(char*) );
3443                 new_argv[0] = argv[0];
3444                 new_argv[1] = "--no-vlc-dylib-path";
3445                 for (i = 1; i < argc; i++)
3446                     new_argv[i+1] = argv[i];
3447                 new_argv[i+1] = NULL;
3448                 execv(new_argv[0], (char* const*)new_argv);
3449             }
3450         }
3451     }
3452 #endif
3453
3454     if( update )
3455     {
3456         return 0;
3457     }
3458
3459     if( input == NULL || *input == '\0' )
3460     {
3461         fprintf( stderr, "Missing input device. Run %s --help for "
3462                  "syntax.\n", argv[0] );
3463         return 1;
3464     }
3465
3466     /* Parse format */
3467     if( titleindex > 0 && !titlescan )
3468     {
3469         if( output == NULL || *output == '\0' )
3470         {
3471             fprintf( stderr, "Missing output file name. Run %s --help "
3472                      "for syntax.\n", argv[0] );
3473             return 1;
3474         }
3475
3476         if( !format )
3477         {
3478             char * p = strrchr( output, '.' );
3479
3480             /* autodetect */
3481             if( p && ( !strcasecmp( p, ".mp4" )  ||
3482                        !strcasecmp( p, ".m4v" ) ) )
3483             {
3484                 mux = HB_MUX_MP4;
3485             }
3486             else if( p && !strcasecmp(p, ".mkv" ) )
3487             {
3488                 mux = HB_MUX_MKV;
3489 #ifndef __APPLE_CC__
3490                 // default to Lame for MKV (except under OS X where Core Audio is available)
3491                 default_acodec = HB_ACODEC_LAME;
3492 #endif
3493             }
3494             else
3495             {
3496                 fprintf( stderr, "Output format couldn't be guessed "
3497                          "from file name, using default.\n" );
3498                 return 0;
3499             }
3500         }
3501         else if( !strcasecmp( format, "mp4" ) ||
3502                  !strcasecmp( format, "m4v" ) )
3503         {
3504             mux = HB_MUX_MP4;
3505         }
3506         else if( !strcasecmp( format, "mkv" ) )
3507         {
3508             mux = HB_MUX_MKV;
3509 #ifndef __APPLE_CC__
3510             // default to Lame for MKV (except under OS X where Core Audio is available)
3511             default_acodec = HB_ACODEC_LAME;
3512 #endif
3513         }
3514         else
3515         {
3516             fprintf( stderr, "Invalid output format (%s). Possible "
3517                      "choices are mp4, m4v and mkv\n.", format );
3518             return 1;
3519         }
3520     }
3521
3522     return 0;
3523 }
3524
3525 static int get_acodec_for_string( char *codec )
3526 {
3527     if( !strcasecmp( codec, "ac3" ) )
3528     {
3529         return HB_ACODEC_AC3;
3530     }
3531     else if( !strcasecmp( codec, "copy" ) )
3532     {
3533         return HB_ACODEC_AC3_PASS | HB_ACODEC_DCA_PASS;
3534     }
3535     else if( !strcasecmp( codec, "copy:ac3" ) )
3536     {
3537         return HB_ACODEC_AC3_PASS;
3538     }
3539     else if( !strcasecmp( codec, "copy:dts" ) || !strcasecmp( codec, "copy:dca" ) )
3540     {
3541         return HB_ACODEC_DCA_PASS;
3542     }
3543     else if( !strcasecmp( codec, "lame" ) )
3544     {
3545         return HB_ACODEC_LAME;
3546     }
3547     else if( !strcasecmp( codec, "faac" ) )
3548     {
3549         return HB_ACODEC_FAAC;
3550     }
3551     else if( !strcasecmp( codec, "vorbis") )
3552     {
3553         return HB_ACODEC_VORBIS;
3554     }
3555 #ifdef __APPLE__
3556     else if( !strcasecmp( codec, "ca_aac") )
3557     {
3558         return HB_ACODEC_CA_AAC;
3559     }
3560 #endif
3561     else
3562     {
3563         return -1;
3564     }
3565 }
3566
3567 static int is_sample_rate_valid(int rate)
3568 {
3569     int i;
3570     for( i = 0; i < hb_audio_rates_count; i++ )
3571     {
3572             if (rate == hb_audio_rates[i].rate)
3573                 return 1;
3574     }
3575     return 0;
3576 }
3577
3578 #ifdef __APPLE_CC__
3579 /****************************************************************************
3580  * bsd_name_for_path
3581  *
3582  * Returns the BSD device name for the block device that contains the
3583  * passed-in path. Returns NULL on failure.
3584  ****************************************************************************/
3585 static char* bsd_name_for_path(char *path)
3586 {
3587     OSStatus err;
3588     FSRef ref;
3589     err = FSPathMakeRef( (const UInt8 *) input, &ref, NULL );
3590     if( err != noErr )
3591     {
3592         return NULL;
3593     }
3594
3595     // Get the volume reference number.
3596     FSCatalogInfo catalogInfo;
3597     err = FSGetCatalogInfo( &ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL,
3598                             NULL);
3599     if( err != noErr )
3600     {
3601         return NULL;
3602     }
3603     FSVolumeRefNum volRefNum = catalogInfo.volume;
3604
3605     // Now let's get the device name
3606     GetVolParmsInfoBuffer volumeParms;
3607     err = FSGetVolumeParms( volRefNum, &volumeParms, sizeof( volumeParms ) );
3608     if( err != noErr )
3609     {
3610         return NULL;
3611     }
3612
3613     // A version 4 GetVolParmsInfoBuffer contains the BSD node name in the vMDeviceID field.
3614     // It is actually a char * value. This is mentioned in the header CoreServices/CarbonCore/Files.h.
3615     if( volumeParms.vMVersion < 4 )
3616     {
3617         return NULL;
3618     }
3619
3620     // vMDeviceID might be zero as is reported with experimental ZFS (zfs-119) support in Leopard.
3621     if( !volumeParms.vMDeviceID )
3622     {
3623         return NULL;
3624     }
3625
3626     return strdup( volumeParms.vMDeviceID );
3627 }
3628
3629 /****************************************************************************
3630  * device_is_dvd
3631  *
3632  * Returns whether or not the passed in BSD device represents a DVD, or other
3633  * optical media.
3634  ****************************************************************************/
3635 static int device_is_dvd(char *device)
3636 {
3637     io_service_t service = get_iokit_service(device);
3638     if( service == IO_OBJECT_NULL )
3639     {
3640         return 0;
3641     }
3642     int result = is_dvd_service(service);
3643     IOObjectRelease(service);
3644     return result;
3645 }
3646
3647 /****************************************************************************
3648  * get_iokit_service
3649  *
3650  * Returns the IOKit service object for the passed in BSD device name.
3651  ****************************************************************************/
3652 static io_service_t get_iokit_service( char *device )
3653 {
3654     CFMutableDictionaryRef matchingDict;
3655     matchingDict = IOBSDNameMatching( kIOMasterPortDefault, 0, device );
3656     if( matchingDict == NULL )
3657     {
3658         return IO_OBJECT_NULL;
3659     }
3660     // Fetch the object with the matching BSD node name. There should only be
3661     // one match, so IOServiceGetMatchingService is used instead of
3662     // IOServiceGetMatchingServices to simplify the code.
3663     return IOServiceGetMatchingService( kIOMasterPortDefault, matchingDict );
3664 }
3665
3666 /****************************************************************************
3667  * is_dvd_service
3668  *
3669  * Returns whether or not the service passed in is a DVD.
3670  *
3671  * Searches for an IOMedia object that represents the entire (whole) media that
3672  * the volume is on. If the volume is on partitioned media, the whole media
3673  * object will be a parent of the volume's media object. If the media is not
3674  * partitioned, the volume's media object will be the whole media object.
3675  ****************************************************************************/
3676 static int is_dvd_service( io_service_t service )
3677 {
3678     kern_return_t  kernResult;
3679     io_iterator_t  iter;
3680
3681     // Create an iterator across all parents of the service object passed in.
3682     kernResult = IORegistryEntryCreateIterator( service,
3683                                                 kIOServicePlane,
3684                                                 kIORegistryIterateRecursively | kIORegistryIterateParents,
3685                                                 &iter );
3686     if( kernResult != KERN_SUCCESS )
3687     {
3688         return 0;
3689     }
3690     if( iter == IO_OBJECT_NULL )
3691     {
3692         return 0;
3693     }
3694
3695     // A reference on the initial service object is released in the do-while
3696     // loop below, so add a reference to balance.
3697     IOObjectRetain( service );
3698
3699     int result = 0;
3700     do
3701     {
3702         if( is_whole_media_service( service ) &&
3703             IOObjectConformsTo( service, kIODVDMediaClass) )
3704         {
3705             result = 1;
3706         }
3707         IOObjectRelease( service );
3708     } while( !result && (service = IOIteratorNext( iter )) );
3709     IOObjectRelease( iter );
3710
3711     return result;
3712 }
3713
3714 /****************************************************************************
3715  * is_whole_media_service
3716  *
3717  * Returns whether or not the service passed in is an IOMedia service and
3718  * represents the "whole" media instead of just a partition.
3719  *
3720  * The whole media object is indicated in the IORegistry by the presence of a
3721  * property with the key "Whole" and value "Yes".
3722  ****************************************************************************/
3723 static int is_whole_media_service( io_service_t service )
3724 {
3725     int result = 0;
3726
3727     if( IOObjectConformsTo( service, kIOMediaClass ) )
3728     {
3729         CFTypeRef wholeMedia = IORegistryEntryCreateCFProperty( service,
3730                                                                 CFSTR( kIOMediaWholeKey ),
3731                                                                 kCFAllocatorDefault,
3732                                                                 0 );
3733         if ( !wholeMedia )
3734         {
3735             return 0;
3736         }
3737         result = CFBooleanGetValue( (CFBooleanRef)wholeMedia );
3738         CFRelease( wholeMedia );
3739     }
3740
3741     return result;
3742 }
3743 #endif // __APPLE_CC__