OSDN Git Service

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