OSDN Git Service

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