OSDN Git Service

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