OSDN Git Service

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