OSDN Git Service

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