OSDN Git Service

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