OSDN Git Service

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