OSDN Git Service

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