OSDN Git Service

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