OSDN Git Service

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