OSDN Git Service

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