X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=test%2Ftest.c;h=fc753d24f09ccf2a3b531f9beabb966f53ad7912;hb=3166f4bf518b12ef658ce4a249f9a265b16693bd;hp=7b4c67899f2cf5621512451ec5923fb54ed36388;hpb=193ed51e0fc2fd74d30a64bff11f2417981587a7;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/test/test.c b/test/test.c index 7b4c6789..fc753d24 100644 --- a/test/test.c +++ b/test/test.c @@ -11,10 +11,18 @@ #include #include +#if defined( __MINGW32__ ) +#include +#endif + +#if defined( PTW32_STATIC_LIB ) +#include +#endif + #include "hb.h" #include "parsecsv.h" -#ifdef __APPLE_CC__ +#if defined( __APPLE_CC__ ) #import #include #include @@ -22,16 +30,23 @@ #endif /* Options */ -static int debug = HB_DEBUG_NONE; +#if defined( __APPLE_CC__ ) +#define EXTRA_VLC_DYLD_PATH "/Applications/VLC.app/Contents/MacOS/lib" +#define DEFAULT_DYLD_PATH "/usr/local/lib:/usr/lib" + +static int no_vlc_dylib = 0; +#endif +static int debug = HB_DEBUG_ALL; static int update = 0; +static int dvdnav = 1; static char * input = NULL; static char * output = NULL; static char * format = NULL; static int titleindex = 1; -static int longest_title = 0; -static int subtitle_scan = 0; -static int subtitle_force = 0; +static int titlescan = 0; +static int main_feature = 0; static char * native_language = NULL; +static int native_dub = 0; static int twoPass = 0; static int deinterlace = 0; static char * deinterlace_opt = 0; @@ -43,10 +58,10 @@ static int detelecine = 0; static char * detelecine_opt = 0; static int decomb = 0; static char * decomb_opt = 0; +static int rotate = 0; +static char * rotate_opt = 0; static int grayscale = 0; static int vcodec = HB_VCODEC_FFMPEG; -static int h264_13 = 0; -static int h264_30 = 0; static hb_list_t * audios = NULL; static hb_audio_config_t * audio = NULL; static int num_audio_tracks = 0; @@ -57,10 +72,22 @@ static char * arates = NULL; static char * abitrates = NULL; static char * acodecs = NULL; static char * anames = NULL; +#ifdef __APPLE_CC__ +static int default_acodec = HB_ACODEC_CA_AAC; +#else static int default_acodec = HB_ACODEC_FAAC; -static int default_arate = 48000; -static int default_abitrate = 160; -static int sub = 0; +#endif +static int audio_explicit = 0; +static char ** subtracks = NULL; +static char ** subforce = NULL; +static char * subburn = NULL; +static char * subdefault = NULL; +static char ** srtfile = NULL; +static char ** srtcodeset = NULL; +static char ** srtoffset = NULL; +static char ** srtlang = NULL; +static int srtdefault = -1; +static int subtitle_scan = 0; static int width = 0; static int height = 0; static int crop[4] = { -1,-1,-1,-1 }; @@ -70,22 +97,24 @@ static float vquality = -1.0; static int vbitrate = 0; static int size = 0; static int mux = 0; -static int pixelratio = 0; -static int loosePixelratio = 0; +static int anamorphic_mode = 0; static int modulus = 0; static int par_height = 0; static int par_width = 0; +static int display_width = 0; +static int keep_display_aspect = 0; +static int itu_par = 0; +static int angle = 0; static int chapter_start = 0; static int chapter_end = 0; static int chapter_markers = 0; static char * marker_file = NULL; -static int crf = 1; static char *x264opts = NULL; static char *x264opts2 = NULL; static int maxHeight = 0; static int maxWidth = 0; static int turbo_opts_enabled = 0; -static char * turbo_opts = "ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0"; +static char * turbo_opts = "ref=1:subme=2:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0"; static int largeFileSize = 0; static int preset = 0; static char * preset_name = 0; @@ -96,10 +125,15 @@ static int color_matrix = 0; static int preview_count = 10; static int store_previews = 0; static int start_at_preview = 0; +static int64_t start_at_pts = 0; +static int start_at_frame = 0; +static char * start_at_string = NULL; +static char * start_at_token = NULL; static int64_t stop_at_pts = 0; static int stop_at_frame = 0; static char * stop_at_string = NULL; static char * stop_at_token = NULL; +static uint64_t min_title_duration = 900000LL; /* Exit cleanly on Ctrl-C */ static volatile int die = 0; @@ -122,7 +156,7 @@ static char* bsd_name_for_path(char *path); static int device_is_dvd(char *device); static io_service_t get_iokit_service( char *device ); static int is_dvd_service( io_service_t service ); -static is_whole_media_service( io_service_t service ); +static int is_whole_media_service( io_service_t service ); #endif /* Only print the "Muxing..." message once */ @@ -145,6 +179,14 @@ int main( int argc, char ** argv ) int build; char * version; +/* win32 _IOLBF (line-buffering) is the same as _IOFBF (full-buffering). + * force it to unbuffered otherwise informative output is not easily parsed. + */ +#if defined( _WIN32 ) || defined( __MINGW32__ ) + setvbuf( stdout, NULL, _IONBF, 0 ); + setvbuf( stderr, NULL, _IONBF, 0 ); +#endif + audios = hb_list_init(); /* Parse command line */ @@ -159,6 +201,7 @@ int main( int argc, char ** argv ) /* Init libhb */ h = hb_init( debug, update ); + hb_dvd_set_dvdnav( dvdnav ); /* Show version */ fprintf( stderr, "%s - %s - %s\n", @@ -179,6 +222,7 @@ int main( int argc, char ** argv ) "date.\n" ); } hb_close( &h ); + hb_global_close(); return 0; } @@ -198,19 +242,41 @@ int main( int argc, char ** argv ) /* Feed libhb with a DVD to scan */ fprintf( stderr, "Opening %s...\n", input ); - if (longest_title) { + if (main_feature) { /* - * We need to scan for all the titles in order to find the longest + * We need to scan for all the titles in order to find the main feature */ titleindex = 0; } - hb_scan( h, input, titleindex, preview_count, store_previews ); + hb_scan( h, input, titleindex, preview_count, store_previews, min_title_duration ); /* Wait... */ while( !die ) { -#if !defined(SYS_BEOS) +#if defined( __MINGW32__ ) + if( _kbhit() ) { + switch( _getch() ) + { + case 0x03: /* ctrl-c */ + case 'q': + fprintf( stdout, "\nEncoding Quit by user command\n" ); + die = 1; + break; + case 'p': + fprintf( stdout, "\nEncoding Paused by user command, 'r' to resume\n" ); + hb_pause( h ); + break; + case 'r': + hb_resume( h ); + break; + case 'h': + ShowCommands(); + break; + } + } + hb_snooze( 200 ); +#elif !defined(SYS_BEOS) fd_set fds; struct timeval tv; int ret; @@ -268,6 +334,7 @@ int main( int argc, char ** argv ) /* Clean up */ hb_close( &h ); + hb_global_close(); if( input ) free( input ); if( output ) free( output ); if( format ) free( format ); @@ -296,7 +363,10 @@ int main( int argc, char ** argv ) if( x264opts2 ) free (x264opts2 ); if (preset_name) free (preset_name); if( stop_at_string ) free( stop_at_string ); + if( start_at_string ) free( start_at_string ); + // write a carriage return to stdout - avoids overlap / line wrapping when stderr is redirected + fprintf( stdout, "\n" ); fprintf( stderr, "HandBrake has exited.\n" ); return 0; @@ -314,18 +384,32 @@ static void ShowCommands() static void PrintTitleInfo( hb_title_t * title ) { hb_chapter_t * chapter; - hb_audio_config_t * audio; hb_subtitle_t * subtitle; int i; fprintf( stderr, "+ title %d:\n", title->index ); - fprintf( stderr, " + vts %d, ttn %d, cells %d->%d (%d blocks)\n", - title->vts, title->ttn, title->cell_start, title->cell_end, - title->block_count ); + if ( title->index == title->job->feature ) + { + fprintf( stderr, " + Main Feature\n" ); + } + if ( title->type == HB_STREAM_TYPE ) + { + fprintf( stderr, " + stream: %s\n", title->path ); + } + else if ( title->type == HB_DVD_TYPE ) + { + fprintf( stderr, " + vts %d, ttn %d, cells %d->%d (%"PRIu64" blocks)\n", + title->vts, title->ttn, title->cell_start, title->cell_end, + title->block_count ); + } + if (title->angle_count > 1) + fprintf( stderr, " + angle(s) %d\n", title->angle_count ); fprintf( stderr, " + duration: %02d:%02d:%02d\n", title->hours, title->minutes, title->seconds ); - fprintf( stderr, " + size: %dx%d, aspect: %.2f, %.3f fps\n", + fprintf( stderr, " + size: %dx%d, pixel aspect: %d/%d, display aspect: %.2f, %.3f fps\n", title->width, title->height, + title->pixel_aspect_width, + title->pixel_aspect_height, (float) title->aspect, (float) title->rate / title->rate_base ); fprintf( stderr, " + autocrop: %d/%d/%d/%d\n", title->crop[0], @@ -334,7 +418,7 @@ static void PrintTitleInfo( hb_title_t * title ) for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) { chapter = hb_list_item( title->list_chapter, i ); - fprintf( stderr, " + %d: cells %d->%d, %d blocks, duration " + fprintf( stderr, " + %d: cells %d->%d, %"PRIu64" blocks, duration " "%02d:%02d:%02d\n", chapter->index, chapter->cell_start, chapter->cell_end, chapter->block_count, chapter->hours, chapter->minutes, @@ -346,20 +430,30 @@ static void PrintTitleInfo( hb_title_t * title ) audio = hb_list_audio_config_item( title->list_audio, i ); if( ( audio->in.codec == HB_ACODEC_AC3 ) || ( audio->in.codec == HB_ACODEC_DCA) ) { - fprintf( stderr, " + %d, %s, %dHz, %dbps\n", i + 1, - audio->lang.description, audio->in.samplerate, audio->in.bitrate ); + fprintf( stderr, " + %d, %s (iso639-2: %s), %dHz, %dbps\n", + i + 1, + audio->lang.description, + audio->lang.iso639_2, + audio->in.samplerate, + audio->in.bitrate ); } else { - fprintf( stderr, " + %d, %s\n", i + 1, audio->lang.description ); + fprintf( stderr, " + %d, %s (iso639-2: %s)\n", + i + 1, + audio->lang.description, + audio->lang.iso639_2 ); } } fprintf( stderr, " + subtitle tracks:\n" ); for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) { subtitle = hb_list_item( title->list_subtitle, i ); - fprintf( stderr, " + %d, %s (iso639-2: %s)\n", i + 1, subtitle->lang, - subtitle->iso639_2); + fprintf( stderr, " + %d, %s (iso639-2: %s) (%s)(%s)\n", + i + 1, subtitle->lang, + subtitle->iso639_2, + (subtitle->format == TEXTSUB) ? "Text" : "Bitmap", + hb_subsource_name(subtitle->source)); } if(title->detected_interlacing) @@ -370,6 +464,25 @@ static void PrintTitleInfo( hb_title_t * title ) } +static int test_sub_list( char ** list, int pos ) +{ + int i; + + if ( list == NULL || pos == 0 ) + return 0; + + if ( list[0] == NULL && pos == 1 ) + return 1; + + for ( i = 0; list[i] != NULL; i++ ) + { + int idx = strtol( list[i], NULL, 0 ); + if ( idx == pos ) + return 1; + } + return 0; +} + static int HandleEvents( hb_handle_t * h ) { hb_state_t s; @@ -386,7 +499,7 @@ static int HandleEvents( hb_handle_t * h ) case HB_STATE_SCANNING: /* Show what title is currently being scanned */ fprintf( stderr, "Scanning title %d", p.title_cur ); - if( !titleindex ) + if( !titleindex || titlescan ) fprintf( stderr, " of %d", p.title_count ); fprintf( stderr, "...\n" ); break; @@ -398,6 +511,7 @@ static int HandleEvents( hb_handle_t * h ) hb_title_t * title; hb_job_t * job; int i; + int sub_burned = 0; /* Audio argument string parsing variables */ int acodec = 0; @@ -416,15 +530,15 @@ static int HandleEvents( hb_handle_t * h ) die = 1; break; } - if( longest_title ) - { + if( main_feature ) + { int i; - int longest_title_idx=0; - int longest_title_pos=-1; - int longest_title_time=0; + int main_feature_idx=0; + int main_feature_pos=-1; + int main_feature_time=0; int title_time; - fprintf( stderr, "Searching for longest title...\n" ); + fprintf( stderr, "Searching for main feature title...\n" ); for( i = 0; i < hb_list_count( list ); i++ ) { @@ -432,29 +546,36 @@ static int HandleEvents( hb_handle_t * h ) title_time = (title->hours*60*60 ) + (title->minutes *60) + (title->seconds); fprintf( stderr, " + Title (%d) index %d has length %dsec\n", i, title->index, title_time ); - if( longest_title_time < title_time ) + if( main_feature_time < title_time ) + { + main_feature_time = title_time; + main_feature_pos = i; + main_feature_idx = title->index; + } + if( title->job->feature == title->index ) { - longest_title_time = title_time; - longest_title_pos = i; - longest_title_idx = title->index; + main_feature_time = title_time; + main_feature_pos = i; + main_feature_idx = title->index; + break; } } - if( longest_title_pos == -1 ) + if( main_feature_pos == -1 ) { - fprintf( stderr, "No longest title found.\n" ); + fprintf( stderr, "No main feature title found.\n" ); die = 1; break; } - titleindex = longest_title_idx; - fprintf( stderr, "Found longest title, setting title to %d\n", - longest_title_idx); + titleindex = main_feature_idx; + fprintf( stderr, "Found main feature title, setting title to %d\n", + main_feature_idx); - title = hb_list_item( list, longest_title_pos); + title = hb_list_item( list, main_feature_pos); } else { title = hb_list_item( list, 0 ); } - if( !titleindex ) + if( !titleindex || titlescan ) { /* Scan-only mode, print infos and exit */ int i; @@ -472,7 +593,7 @@ static int HandleEvents( hb_handle_t * h ) PrintTitleInfo( title ); - if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame ) + if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame ) { job->chapter_start = MAX( job->chapter_start, chapter_start ); @@ -482,745 +603,851 @@ static int HandleEvents( hb_handle_t * h ) job->chapter_end ); } + if ( angle ) + { + job->angle = angle; + } + if (preset) { - fprintf( stderr, "+ Using preset: %s", preset_name); + fprintf( stderr, "+ Using preset: %s\n", preset_name); if (!strcmp(preset_name, "Universal")) - { - mux = HB_MUX_MP4; - vcodec = HB_VCODEC_X264; - job->vquality = 0.589999973773956; - job->crf = 1; - if( !atracks ) - { - atracks = strdup("1,1"); - } - if( !abitrates ) - { - abitrates = strdup("160,auto"); - } - if( !arates ) - { - arates = strdup("48,Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac,ac3"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2,auto"); - } - maxWidth = 720; - if( !x264opts ) - { - x264opts = strdup("level=30:cabac=0:ref=3:mixed-refs=1:analyse=all:me=umh:no-fast-pskip=1"); - } - pixelratio = 2; - job->chapter_markers = 1; - } + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + if( !atracks ) + { + atracks = strdup("1,1"); + } + if( !acodecs ) + { + acodecs = strdup("faac,copy:ac3"); + } + if( !abitrates ) + { + abitrates = strdup("160,160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2,auto"); + } + if( !arates ) + { + arates = strdup("Auto,Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0,0.0"); + } + maxWidth = 720; + if( !x264opts ) + { + x264opts = strdup("cabac=0:ref=2:me=umh:bframes=0:weightp=0:8x8dct=0:trellis=0:subme=6"); + } + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "iPod")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->ipod_atom = 1; + vcodec = HB_VCODEC_X264; + job->vbitrate = 700; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + maxWidth = 320; + if( !x264opts ) + { + x264opts = strdup("level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:subme=6:8x8dct=0:trellis=0"); + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "iPhone & iPod Touch")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("128"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + maxWidth = 480; + if( !x264opts ) + { + x264opts = strdup("cabac=0:ref=2:me=umh:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0"); + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "iPhone 4")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->largeFileSize = 1; + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + job->vrate_base = 900900; + job->cfr = 2; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + maxWidth = 960; + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "iPad")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->largeFileSize = 1; + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + job->vrate_base = 900900; + job->cfr = 2; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + maxWidth = 1024; + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "AppleTV")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->largeFileSize = 1; + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + if( !atracks ) + { + atracks = strdup("1,1"); + } + if( !acodecs ) + { + acodecs = strdup("faac,copy:ac3"); + } + if( !abitrates ) + { + abitrates = strdup("160,160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2,auto"); + } + if( !arates ) + { + arates = strdup("Auto,Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0,0.0"); + } + maxWidth = 960; + if( !x264opts ) + { + x264opts = strdup("cabac=0:ref=2:me=umh:b-pyramid=none:b-adapt=2:weightb=0:trellis=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500"); + } + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "AppleTV 2")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->largeFileSize = 1; + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + job->vrate_base = 900900; + job->cfr = 2; + if( !atracks ) + { + atracks = strdup("1,1"); + } + if( !acodecs ) + { + acodecs = strdup("faac,copy:ac3"); + } + if( !abitrates ) + { + abitrates = strdup("160,160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2,auto"); + } + if( !arates ) + { + arates = strdup("Auto,Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0,0.0"); + } + maxWidth = 1280; + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "Normal")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + if( !x264opts ) + { + x264opts = strdup("ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0"); + } + if( !anamorphic_mode ) + { + anamorphic_mode = 1; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "High Profile")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + vcodec = HB_VCODEC_X264; + job->vquality = 20.0; + if( !atracks ) + { + atracks = strdup("1,1"); + } + if( !acodecs ) + { + acodecs = strdup("faac,copy:ac3"); + } + if( !abitrates ) + { + abitrates = strdup("160,160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2,auto"); + } + if( !arates ) + { + arates = strdup("Auto,Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0,0.0"); + } + if( !x264opts ) + { + x264opts = strdup("b-adapt=2:rc-lookahead=50"); + } + detelecine = 1; + decomb = 1; + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "Classic")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->vbitrate = 1000; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + + } + + if (!strcmp(preset_name, "AppleTV Legacy")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->largeFileSize = 1; + vcodec = HB_VCODEC_X264; + job->vbitrate = 2500; + if( !atracks ) + { + atracks = strdup("1,1"); + } + if( !acodecs ) + { + acodecs = strdup("faac,copy:ac3"); + } + if( !abitrates ) + { + abitrates = strdup("160,160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2,auto"); + } + if( !arates ) + { + arates = strdup("Auto,Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0,0.0"); + } + if( !x264opts ) + { + x264opts = strdup("ref=1:b-pyramid=none:weightp=0:subme=5:me=umh:no-fast-pskip=1:cabac=0:weightb=0:8x8dct=0:trellis=0"); + } + if( !anamorphic_mode ) + { + anamorphic_mode = 1; + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "iPhone Legacy")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->ipod_atom = 1; + vcodec = HB_VCODEC_X264; + job->vbitrate = 960; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("128"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + maxWidth = 480; + if( !x264opts ) + { + x264opts = strdup("level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0"); + } + job->chapter_markers = 1; + + } + + if (!strcmp(preset_name, "iPod Legacy")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + job->ipod_atom = 1; + vcodec = HB_VCODEC_X264; + job->vbitrate = 1500; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = strdup("160"); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + maxWidth = 640; + if( !x264opts ) + { + x264opts = strdup("level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subme=6:8x8dct=0:trellis=0"); + } + job->chapter_markers = 1; + + } + + } - if (!strcmp(preset_name, "iPod")) - { - mux = HB_MUX_MP4; - job->ipod_atom = 1; - vcodec = HB_VCODEC_X264; - job->vbitrate = 700; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("160"); - } - if( !arates ) - { - arates = strdup("48"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - maxWidth = 320; - if( !x264opts ) - { - x264opts = strdup("level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1"); - } - job->chapter_markers = 1; - } + if ( chapter_markers ) + { + job->chapter_markers = chapter_markers; - if (!strcmp(preset_name, "iPhone & iPod Touch")) + if( marker_file != NULL ) { - mux = HB_MUX_MP4; - vcodec = HB_VCODEC_X264; - job->vquality = 0.589999973773956; - job->crf = 1; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("128"); - } - if( !arates ) - { - arates = strdup("48"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - maxWidth = 480; - if( !x264opts ) - { - x264opts = strdup("level=30:cabac=0:ref=2:mixed-refs:analyse=all:me=umh:no-fast-pskip=1"); - } - job->chapter_markers = 1; - } + hb_csv_file_t * file = hb_open_csv_file( marker_file ); + hb_csv_cell_t * cell; + int row = 0; + int chapter = 0; - if (!strcmp(preset_name, "AppleTV")) - { - mux = HB_MUX_MP4; - job->largeFileSize = 1; - vcodec = HB_VCODEC_X264; - job->vquality = 0.589999973773956; - job->crf = 1; - if( !atracks ) - { - atracks = strdup("1,1"); - } - if( !abitrates ) - { - abitrates = strdup("160,auto"); - } - if( !arates ) - { - arates = strdup("48,Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac,ac3"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2,auto"); - } - maxWidth = 960; - if( !x264opts ) - { - x264opts = strdup("level=30:cabac=0:ref=3:mixed-refs=1:bframes=6:weightb=1:direct=auto:no-fast-pskip=1:me=umh:subq=7:analyse=all"); - } - pixelratio = 2; - job->chapter_markers = 1; - } + fprintf( stderr, "Reading chapter markers from file %s\n", marker_file ); - if (!strcmp(preset_name, "QuickTime")) - { - mux = HB_MUX_MP4; - vcodec = HB_VCODEC_X264; - job->vbitrate = 1800; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("160"); - } - if( !arates ) - { - arates = strdup("Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) + if( file == NULL ) { - mixdowns = strdup("dpl2"); + fprintf( stderr, "Cannot open chapter marker file, using defaults\n" ); } - if( !x264opts ) + else { - x264opts = strdup("ref=3:mixed-refs:bframes=3:weightb:direct=auto:me=umh:subme=7:analyse=all:8x8dct:trellis=1:no-fast-pskip=1:psy-rd=1,1"); + /* Parse the cells */ + while( NULL != ( cell = hb_read_next_cell( file ) ) ) + { + /* We have a chapter number */ + if( cell->cell_col == 0 ) + { + row = cell->cell_row; + chapter = atoi( cell->cell_text ); + } + + /* We have a chapter name */ + if( cell->cell_col == 1 && row == cell->cell_row ) + { + /* If we have a valid chapter, copy the string an terminate it */ + if( chapter >= job->chapter_start && chapter <= job->chapter_end ) + { + hb_chapter_t * chapter_s; + + chapter_s = hb_list_item( job->title->list_chapter, chapter - 1); + strncpy(chapter_s->title, cell->cell_text, 1023); + chapter_s->title[1023] = '\0'; + } + } + + + hb_dispose_cell( cell ); + } + + hb_close_csv_file( file ); } - pixelratio = 1; - job->chapter_markers = 1; - twoPass = 1; - turbo_opts_enabled = 1; } - - if (!strcmp(preset_name, "AppleTV Legacy")) + else { - mux = HB_MUX_MP4; - job->largeFileSize = 1; - vcodec = HB_VCODEC_X264; - job->vbitrate = 2500; - if( !atracks ) - { - atracks = strdup("1,1"); - } - if( !abitrates ) - { - abitrates = strdup("160,auto"); - } - if( !arates ) - { - arates = strdup("48,Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac,ac3"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2,auto"); - } - if( !x264opts ) + /* No marker file */ + + int number_of_chapters = hb_list_count(job->title->list_chapter); + int chapter; + + for(chapter = 0; chapter <= number_of_chapters - 1 ; chapter++) { - x264opts = strdup("bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:trellis=1:cabac=0"); + hb_chapter_t * chapter_s; + chapter_s = hb_list_item( job->title->list_chapter, chapter); + snprintf( chapter_s->title, 1023, "Chapter %i", chapter + 1 ); + chapter_s->title[1023] = '\0'; } - pixelratio = 1; - job->chapter_markers = 1; } + } - if (!strcmp(preset_name, "iPhone Legacy")) - { - mux = HB_MUX_MP4; - job->ipod_atom = 1; - vcodec = HB_VCODEC_X264; - job->vbitrate = 960; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) + if( crop[0] >= 0 && crop[1] >= 0 && + crop[2] >= 0 && crop[3] >= 0 ) + { + memcpy( job->crop, crop, 4 * sizeof( int ) ); + } + + job->deinterlace = deinterlace; + job->grayscale = grayscale; + + /* Add selected filters */ + job->filters = hb_list_init(); + + if( rotate ) + { + hb_filter_rotate.settings = rotate_opt; + hb_list_add( job->filters, &hb_filter_rotate); + } + if( detelecine ) + { + hb_filter_detelecine.settings = detelecine_opt; + hb_list_add( job->filters, &hb_filter_detelecine ); + } + if( decomb ) + { + hb_filter_decomb.settings = decomb_opt; + hb_list_add( job->filters, &hb_filter_decomb ); + } + if( deinterlace ) + { + hb_filter_deinterlace.settings = deinterlace_opt; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + if( deblock ) + { + hb_filter_deblock.settings = deblock_opt; + hb_list_add( job->filters, &hb_filter_deblock ); + } + if( denoise ) + { + hb_filter_denoise.settings = denoise_opt; + hb_list_add( job->filters, &hb_filter_denoise ); + } + + switch( anamorphic_mode ) + { + case 0: // Non-anamorphic + + if (modulus) { - abitrates = strdup("128"); + job->modulus = modulus; } - if( !arates ) + + if( width && height ) { - arates = strdup("48"); + job->width = width; + job->height = height; } - if( !acodecs ) + else if( width ) { - acodecs = strdup("faac"); + job->width = width; + // do not exceed source dimensions by default + if( !maxHeight ) + job->maxHeight = title->height; + hb_fix_aspect( job, HB_KEEP_WIDTH ); } - if( !mixdowns ) + else if( height ) { - mixdowns = strdup("dpl2"); + job->height = height; + // do not exceed source dimensions by default + if( !maxWidth ) + job->maxWidth = title->width; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); } - maxWidth = 480; - if( !x264opts ) + else if( !width && !height ) { - x264opts = strdup("level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:trellis=1"); + /* Default to cropped width when one isn't specified + * avoids rounding to mod 16 regardless of modulus */ + job->width = title->width - job->crop[2] - job->crop[3]; + // do not exceed source dimensions by default + if( !maxHeight ) + job->maxHeight = title->height; + hb_fix_aspect( job, HB_KEEP_WIDTH ); } - job->chapter_markers = 1; - } - if (!strcmp(preset_name, "iPod Legacy")) - { - mux = HB_MUX_MP4; - job->ipod_atom = 1; - vcodec = HB_VCODEC_X264; - job->vbitrate = 1500; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) + break; + + case 1: // Strict anammorphic + job->anamorphic.mode = anamorphic_mode; + break; + + case 2: // Loose anamorphic + job->anamorphic.mode = 2; + + if (modulus) { - abitrates = strdup("160"); + job->modulus = modulus; } - if( !arates ) + + if( itu_par ) { - arates = strdup("48"); + job->anamorphic.itu_par = itu_par; } - if( !acodecs ) + + if( width ) { - acodecs = strdup("faac"); + job->width = width; } - if( !mixdowns ) + else if( !width && !height ) { - mixdowns = strdup("dpl2"); + /* Default to full width when one isn't specified for loose anamorphic */ + job->width = title->width - job->crop[2] - job->crop[3]; } - maxWidth = 640; - if( !x264opts ) + + break; + + case 3: // Custom Anamorphic 3: Power User Jamboree + job->anamorphic.mode = 3; + + if (modulus) { - x264opts = strdup("level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1"); + job->modulus = modulus; } - job->chapter_markers = 1; - } - - if (!strcmp(preset_name, "Normal")) - { - mux = HB_MUX_MP4; - vcodec = HB_VCODEC_X264; - job->vbitrate = 1500; - if( !atracks ) + + if( itu_par ) { - atracks = strdup("1"); + job->anamorphic.itu_par = itu_par; } - if( !abitrates ) + + if( par_width && par_height ) { - abitrates = strdup("160"); + job->anamorphic.par_width = par_width; + job->anamorphic.par_height = par_height; } - if( !arates ) + + if( keep_display_aspect ) { - arates = strdup("Auto"); + job->anamorphic.keep_display_aspect = 1; + + /* First, what *is* the display aspect? */ + int cropped_width = title->width - job->crop[2] - job->crop[3]; + int cropped_height = title->height - job->crop[0] - job->crop[1]; + + /* XXX -- I'm assuming people want to keep the source + display AR even though they might have already + asked for ITU values instead. */ + float source_display_width = (float)cropped_width * + (float)title->pixel_aspect_width / (float)title->pixel_aspect_height; + float display_aspect = source_display_width / (float)cropped_height; + /* When keeping display aspect, we have to rank some values + by priority in order to consistently handle situations + when more than one might be specified by default. + + * First off, PAR gets ignored. (err make this reality) + * Height will be respected over all other settings, + * If it isn't set, display_width will be followed. + * If it isn't set, width will be followed. */ + if( height ) + { + /* We scale the display width to the new height */ + display_width = (int)( (double)height * display_aspect ); + } + else if( display_width ) + { + /* We scale the height to the new display width */ + height = (int)( (double)display_width / display_aspect ); + } } - if( !acodecs ) + + if( display_width ) { - acodecs = strdup("faac"); + /* Adjust the PAR to create the new display width + from the default job width. */ + job->anamorphic.dar_width = display_width; + + job->anamorphic.dar_height = height ? + height : + title->height - job->crop[0] - job->crop[1]; } - if( !mixdowns ) + + if( width && height ) { - mixdowns = strdup("dpl2"); + /* Use these storage dimensions */ + job->width = width; + job->height = height; } - if( !x264opts ) + else if( width ) { - x264opts = strdup("ref=2:bframes=2:me=umh"); + /* Use just this storage width */ + job->width = width; + job->height = title->height - job->crop[0] - job->crop[1]; } - pixelratio = 1; - job->chapter_markers = 1; - twoPass = 1; - turbo_opts_enabled = 1; - } - - if (!strcmp(preset_name, "Classic")) - { - mux = HB_MUX_MP4; - job->vbitrate = 1000; - if( !atracks ) + else if( height ) { - atracks = strdup("1"); + /* Use just this storage height. */ + job->height = height; + job->width = title->width - job->crop[2] - job->crop[3]; } - if( !abitrates ) + else if( !width && !height ) { - abitrates = strdup("160"); + /* Assume source dimensions after cropping. */ + job->width = title->width - job->crop[2] - job->crop[3]; + job->height = title->height - job->crop[0] - job->crop[1]; } - if( !arates ) - { - arates = strdup("Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - } - - if (!strcmp(preset_name, "Animation")) - { - mux = HB_MUX_MKV; - vcodec = HB_VCODEC_X264; - job->vbitrate = 1000; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("160"); - } - if( !arates ) - { - arates = strdup("Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - if( !x264opts ) - { - x264opts = strdup("ref=5:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip:filter=2,2:psy-rd=1,1:subme=9"); - } - detelecine = 1; - decomb = 1; - pixelratio = 1; - job->chapter_markers = 1; - twoPass = 1; - turbo_opts_enabled = 1; - } - - if (!strcmp(preset_name, "Constant Quality Rate")) - { - mux = HB_MUX_MKV; - vcodec = HB_VCODEC_X264; - job->vquality = 0.600000023841858; - job->crf = 1; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("auto"); - } - if( !arates ) - { - arates = strdup("Auto"); - } - if( !acodecs ) - { - acodecs = strdup("ac3"); - } - if( !mixdowns ) - { - mixdowns = strdup("auto"); - } - if( !x264opts ) - { - x264opts = strdup("ref=3:mixed-refs:bframes=3:b-pyramid:weightb:filter=-2,-1:trellis=1:analyse=all:8x8dct:me=umh:subme=9:psy-rd=1,1"); - } - pixelratio = 1; - job->chapter_markers = 1; - } - - if (!strcmp(preset_name, "Film")) - { - mux = HB_MUX_MKV; - vcodec = HB_VCODEC_X264; - job->vbitrate = 1800; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("auto"); - } - if( !arates ) - { - arates = strdup("Auto"); - } - if( !acodecs ) - { - acodecs = strdup("ac3"); - } - if( !mixdowns ) - { - mixdowns = strdup("auto"); - } - if( !x264opts ) - { - x264opts = strdup("ref=3:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:subme=9:analyse=all:8x8dct:trellis=1:no-fast-pskip:psy-rd=1,1"); - } - pixelratio = 1; - job->chapter_markers = 1; - twoPass = 1; - turbo_opts_enabled = 1; - } - - if (!strcmp(preset_name, "Television")) - { - mux = HB_MUX_MKV; - vcodec = HB_VCODEC_X264; - job->vbitrate = 1300; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("160"); - } - if( !arates ) - { - arates = strdup("Auto"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - if( !x264opts ) - { - x264opts = strdup("ref=3:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:subme=9:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip=1:psy-rd=1,1"); - } - detelecine = 1; - decomb = 1; - pixelratio = 1; - job->chapter_markers = 1; - twoPass = 1; - turbo_opts_enabled = 1; - } - - if (!strcmp(preset_name, "PSP")) - { - mux = HB_MUX_MP4; - job->vbitrate = 1024; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("128"); - } - if( !arates ) - { - arates = strdup("48"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - maxWidth = 368; - maxHeight = 208; - job->chapter_markers = 1; - } - - if (!strcmp(preset_name, "PS3")) - { - mux = HB_MUX_MP4; - vcodec = HB_VCODEC_X264; - job->vbitrate = 2500; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("160"); - } - if( !arates ) - { - arates = strdup("48"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - job->crop[0] = 0; - job->crop[1] = 0; - job->crop[2] = 0; - job->crop[4] - 0; - if( !x264opts ) - { - x264opts = strdup("level=41:me=umh"); - } - pixelratio = 1; - } - - if (!strcmp(preset_name, "Xbox 360")) - { - mux = HB_MUX_MP4; - vcodec = HB_VCODEC_X264; - job->vbitrate = 2000; - if( !atracks ) - { - atracks = strdup("1"); - } - if( !abitrates ) - { - abitrates = strdup("160"); - } - if( !arates ) - { - arates = strdup("48"); - } - if( !acodecs ) - { - acodecs = strdup("faac"); - } - if( !mixdowns ) - { - mixdowns = strdup("dpl2"); - } - if( !x264opts ) - { - x264opts = strdup("level=40:ref=2:mixed-refs:bframes=3:weightb:subme=9:direct=auto:b-pyramid:me=umh:analyse=all:no-fast-pskip:filter=-2,-1"); - } - pixelratio = 1; - } - } - - if ( chapter_markers ) - { - job->chapter_markers = chapter_markers; - - if( marker_file != NULL ) - { - hb_csv_file_t * file = hb_open_csv_file( marker_file ); - hb_csv_cell_t * cell; - int row = 0; - int chapter = 0; - - fprintf( stderr, "Reading chapter markers from file %s\n", marker_file ); - - if( file == NULL ) - { - fprintf( stderr, "Cannot open chapter marker file, using defaults\n" ); - } - else - { - /* Parse the cells */ - while( NULL != ( cell = hb_read_next_cell( file ) ) ) - { - /* We have a chapter number */ - if( cell->cell_col == 0 ) - { - row = cell->cell_row; - chapter = atoi( cell->cell_text ); - } - - /* We have a chapter name */ - if( cell->cell_col == 1 && row == cell->cell_row ) - { - /* If we have a valid chapter, copy the string an terminate it */ - if( chapter >= job->chapter_start && chapter <= job->chapter_end ) - { - hb_chapter_t * chapter_s; - - chapter_s = hb_list_item( job->title->list_chapter, chapter - 1); - strncpy(chapter_s->title, cell->cell_text, 1023); - chapter_s->title[1023] = '\0'; - } - } - - - hb_dispose_cell( cell ); - } - - hb_close_csv_file( file ); - } - } - else - { - /* No marker file */ - - int number_of_chapters = hb_list_count(job->title->list_chapter); - int chapter; - - for(chapter = 0; chapter <= number_of_chapters - 1 ; chapter++) - { - hb_chapter_t * chapter_s; - chapter_s = hb_list_item( job->title->list_chapter, chapter); - snprintf( chapter_s->title, 1023, "Chapter %i", chapter + 1 ); - chapter_s->title[1023] = '\0'; - } - } - } - - if( crop[0] >= 0 && crop[1] >= 0 && - crop[2] >= 0 && crop[3] >= 0 ) - { - memcpy( job->crop, crop, 4 * sizeof( int ) ); - } - - job->deinterlace = deinterlace; - job->grayscale = grayscale; - if (loosePixelratio) - { - job->anamorphic.mode = 2; - if (modulus) - { - job->anamorphic.modulus = modulus; - } - if( par_width && par_height ) - { - job->anamorphic.mode = 3; - job->anamorphic.par_width = par_width; - job->anamorphic.par_height = par_height; - } - } - else - { - job->anamorphic.mode = pixelratio; - } - - /* Add selected filters */ - job->filters = hb_list_init(); - if( detelecine ) - { - hb_filter_detelecine.settings = detelecine_opt; - hb_list_add( job->filters, &hb_filter_detelecine ); - - if( !vrate ) - { - /* No framerate specified, so using same as source. - That means VFR, so set detelecine up to drop frames. */ - job->vfr = 1; - } - } - if( decomb ) - { - hb_filter_decomb.settings = decomb_opt; - hb_list_add( job->filters, &hb_filter_decomb ); - } - if( deinterlace ) - { - hb_filter_deinterlace.settings = deinterlace_opt; - hb_list_add( job->filters, &hb_filter_deinterlace ); - } - if( deblock ) - { - hb_filter_deblock.settings = deblock_opt; - hb_list_add( job->filters, &hb_filter_deblock ); - } - if( denoise ) - { - hb_filter_denoise.settings = denoise_opt; - hb_list_add( job->filters, &hb_filter_denoise ); - } - - if( width && height ) - { - job->width = width; - job->height = height; - } - else if( width ) - { - job->width = width; - hb_fix_aspect( job, HB_KEEP_WIDTH ); - } - else if( height && !loosePixelratio) - { - job->height = height; - hb_fix_aspect( job, HB_KEEP_HEIGHT ); - } - else if( !width && !height && !pixelratio && !loosePixelratio ) - { - hb_fix_aspect( job, HB_KEEP_WIDTH ); - } - else if (!width && loosePixelratio) - { - /* Default to full width when one isn't specified for loose anamorphic */ - job->width = title->width - job->crop[2] - job->crop[3]; - /* The height will be thrown away in hb.c but calculate it anyway */ - hb_fix_aspect( job, HB_KEEP_WIDTH ); + + break; } - if( vquality >= 0.0 && ( ( vquality <= 1.0 ) || ( vcodec == HB_VCODEC_X264 ) || (vcodec == HB_VCODEC_FFMPEG) ) ) + if( vquality >= 0.0 ) { job->vquality = vquality; job->vbitrate = 0; @@ -1234,20 +1461,20 @@ static int HandleEvents( hb_handle_t * h ) { job->vcodec = vcodec; } - if( h264_13 ) - { - job->h264_level = 13; - } - if( h264_30 ) - { - job->h264_level = 30; - } if( vrate ) { - job->cfr = 1; + job->cfr = cfr; job->vrate = 27000000; job->vrate_base = vrate; } + else if ( cfr ) + { + // cfr or pfr flag with no rate specified implies + // use the title rate. + job->cfr = cfr; + job->vrate = title->rate; + job->vrate_base = title->rate_base; + } /* Grab audio tracks */ if( atracks ) @@ -1286,7 +1513,7 @@ static int HandleEvents( hb_handle_t * h ) } else { - fprintf(stderr, "ERROR: Unable to parse audio input \"%s\", skipping.", + fprintf(stderr, "ERROR: Unable to parse audio input \"%s\", skipping.\n", token); free(audio); } @@ -1302,8 +1529,59 @@ static int HandleEvents( hb_handle_t * h ) } /* Parse audio tracks */ - if( hb_list_count(audios) == 0 ) + if( native_language && native_dub ) { + if( hb_list_count( audios ) == 0 || !audio_explicit ) + { + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + char audio_lang[4]; + int track = i; + + audio = hb_list_audio_config_item( title->list_audio, i ); + + strncpy( audio_lang, audio->lang.iso639_2, sizeof( audio_lang ) ); + + if( strncasecmp( native_language, audio_lang, + sizeof( audio_lang ) ) == 0 && + audio->lang.type != 3 && // Directors 1 + audio->lang.type != 4) // Directors 2 + { + /* + * Matched an audio to our native language - use it. + * Replace any existing audio tracks that a preset may + * have put here. + */ + if( hb_list_count(audios) == 0) { + audio = calloc(1, sizeof(*audio)); + hb_audio_config_init(audio); + audio->in.track = track; + audio->out.track = num_audio_tracks++; + /* Add it to our audios */ + hb_list_add(audios, audio); + } else { + /* + * Update the track numbers on what is already in + * there. + */ + for( i=0; i < hb_list_count( audios ); i++ ) + { + audio = hb_list_item( audios, i ); + + audio->in.track = track; + } + } + break; + } + } + } else { + fprintf( stderr, "Warning: Native language (dubbing) selection ignored since an audio track has already been selected\n"); + } + } + + if( hb_list_count(audios) == 0 && + hb_list_count(job->title->list_audio) > 0 ) + { /* Create a new audio track with default settings */ audio = calloc(1, sizeof(*audio)); hb_audio_config_init(audio); @@ -1422,6 +1700,10 @@ static int HandleEvents( hb_handle_t * h ) if( audio != NULL ) { + if ( !strcasecmp( token, "auto" ) ) + { + arate = audio->in.samplerate; + } if (!is_sample_rate_valid(arate)) { fprintf(stderr, "Invalid sample rate %d, using input rate %d\n", arate, audio->in.samplerate); @@ -1453,6 +1735,52 @@ static int HandleEvents( hb_handle_t * h ) } } /* Sample Rate */ + + /* Audio Mixdown */ + i = 0; + if ( mixdowns ) + { + char * token = strtok(mixdowns, ","); + if (token == NULL) + token = mixdowns; + while ( token != NULL ) + { + mixdown = hb_mixdown_get_mixdown_from_short_name(token); + audio = hb_list_audio_config_item(job->list_audio, i); + if( audio != NULL ) + { + audio->out.mixdown = mixdown; + if( (++i) >= num_audio_tracks ) + break; /* We have more inputs than audio tracks, oops */ + } + else + { + fprintf(stderr, "Ignoring mixdown, no audio tracks\n"); + } + token = strtok(NULL, ","); + } + } + if (i < num_audio_tracks) + { + /* We have fewer inputs than audio tracks, use the default mixdown for the rest. Unless + * we only have one input, then use that. + */ + int use_default = 0; + if (i != 1) + use_default = 1; + + for (; i < num_audio_tracks; i++) + { + audio = hb_list_audio_config_item(job->list_audio, i); + if (use_default) + { + // Get default for this tracks codec and layout + mixdown = hb_get_default_mixdown( audio->out.codec, audio->in.channel_layout ); + } + audio->out.mixdown = mixdown; + } + } + /* Audio Mixdown */ /* Audio Bitrate */ i = 0; @@ -1485,11 +1813,19 @@ static int HandleEvents( hb_handle_t * h ) * for the remaining tracks. Unless we only have one input, then use * that for all tracks. */ + int use_default = 0; if (i != 1) - abitrate = default_abitrate; + use_default = 1; + for (; i < num_audio_tracks; i++) { audio = hb_list_audio_config_item(job->list_audio, i); + if (use_default) + { + abitrate = hb_get_default_audio_bitrate( + audio->out.codec, audio->out.samplerate, + audio->out.mixdown ); + } audio->out.bitrate = abitrate; } } @@ -1535,96 +1871,296 @@ static int HandleEvents( hb_handle_t * h ) } /* Audio DRC */ - /* Audio Mixdown */ + /* Audio Track Names */ i = 0; - if ( mixdowns ) + if ( anames ) { - char * token = strtok(mixdowns, ","); + char * token = strtok(anames, ","); if (token == NULL) - token = mixdowns; + token = anames; while ( token != NULL ) { - mixdown = hb_mixdown_get_mixdown_from_short_name(token); audio = hb_list_audio_config_item(job->list_audio, i); if( audio != NULL ) { - audio->out.mixdown = mixdown; + audio->out.name = strdup(token); if( (++i) >= num_audio_tracks ) - break; /* We have more inputs than audio tracks, oops */ + break; /* We have more names than audio tracks, oops */ } else { - fprintf(stderr, "Ignoring mixdown, no audio tracks\n"); + fprintf(stderr, "Ignoring aname '%s', no audio track\n", + token); } token = strtok(NULL, ","); } } - if (i < num_audio_tracks) + if( i < num_audio_tracks && i == 1 ) { - /* We have fewer inputs than audio tracks, use DPLII for the rest. Unless - * we only have one input, then use that. - */ - if (i != 1) - mixdown = HB_AMIXDOWN_DOLBYPLII; - for (; i < num_audio_tracks; i++) + /* We have exactly one name and more than one audio track. Use the same + * name for all tracks. */ + for ( ; i < num_audio_tracks; i++) { - audio = hb_list_audio_config_item(job->list_audio, i); - audio->out.mixdown = mixdown; + audio = hb_list_audio_config_item(job->list_audio, i); + audio->out.name = strdup(anames); } } - /* Audio Mixdown */ - /* Audio Track Names */ - i = 0; - if ( anames ) + + /* Fix up passthru that needs to fallback to ac3 encode */ + for( i = 0; i < hb_list_count( job->list_audio ); ) { - char * token = strtok(anames, ","); - if (token == NULL) - token = anames; - while ( token != NULL ) + audio = hb_list_audio_config_item( job->list_audio, i ); + if ( ( audio->out.codec & HB_ACODEC_AC3 ) && + ( audio->out.codec & HB_ACODEC_PASS_FLAG ) && + !( audio->out.codec & audio->in.codec ) ) { - audio = hb_list_audio_config_item(job->list_audio, i); - if( audio != NULL ) + // AC3 passthru not possible, fallback to AC3 encoder. + fprintf( stderr, "AC3 passthru requested and input codec is not AC3 for track %d, using AC3 encoder\n", + audio->out.track ); + audio->out.codec = HB_ACODEC_AC3; + audio->out.mixdown = hb_get_default_mixdown( audio->out.codec, audio->in.channel_layout ); + audio->out.bitrate = hb_get_default_audio_bitrate( audio->out.codec, audio->out.samplerate, + audio->out.mixdown ); + } + // fix 'copy' to select a specific codec + if ( audio->out.codec & HB_ACODEC_PASS_FLAG ) + { + audio->out.codec &= (audio->in.codec | HB_ACODEC_PASS_FLAG); + if ( !( audio->out.codec & HB_ACODEC_MASK ) ) { - audio->out.name = strdup(token); - if( (++i) >= num_audio_tracks ) - break; /* We have more names than audio tracks, oops */ + // Passthru not possible, drop audio. + fprintf( stderr, "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n", + audio->out.track ); + hb_audio_t * item = hb_list_item( job->list_audio, i ); + hb_list_rem( job->list_audio, item ); + continue; + } + } + i++; + } + + if( size ) + { + job->vbitrate = hb_calc_bitrate( job, size ); + fprintf( stderr, "Calculated bitrate: %d kbps\n", + job->vbitrate ); + } + + if( subtracks ) + { + char * token; + int i; + int burnpos = 0, defaultpos = 0; + + if ( subburn ) + burnpos = strtol( subburn, NULL, 0 ); + if ( subdefault ) + defaultpos = strtol( subdefault, NULL, 0 ); + for ( i = 0; subtracks[i] != NULL; i++ ) + { + token = subtracks[i]; + if( strcasecmp(token, "scan" ) == 0 ) + { + int burn = 0, force = 0, def = 0; + + if ( subburn != NULL ) + { + burn = ( i == 0 && subburn[0] == 0 ) || + ( burnpos == i+1 ); + } + if ( subdefault != NULL ) + { + def = ( i == 0 && subdefault[0] == 0 ) || + ( defaultpos == i+1 ); + } + force = test_sub_list( subforce, i+1 ); + + if ( !burn ) + { + job->select_subtitle_config.dest = PASSTHRUSUB; + } + else + { + if ( sub_burned ) + { + continue; + } + sub_burned = 1; + } + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; + subtitle_scan = 1; } else { - fprintf(stderr, "Ignoring aname '%s', no audio track\n", - token); + hb_subtitle_t * subtitle; + hb_subtitle_config_t sub_config; + int track; + int burn = 0, force = 0, def = 0; + + track = atoi(token) - 1; + subtitle = hb_list_item(title->list_subtitle, track); + if( subtitle == NULL ) + { + fprintf( stderr, "Warning: Could not find subtitle track %d, skipped\n", track+1 ); + continue; + } + sub_config = subtitle->config; + + if ( subburn != NULL ) + { + burn = ( i == 0 && subburn[0] == 0 ) || + ( burnpos == i+1 ); + } + if ( subdefault != NULL ) + { + def = ( i == 0 && subdefault[0] == 0 ) || + ( defaultpos == i+1 ); + } + + force = test_sub_list(subforce, i+1); + + int supports_burn = + ( subtitle->source == VOBSUB ) || + ( subtitle->source == SSASUB ); + + if ( burn && supports_burn ) + { + // Only allow one subtitle to be burned into video + if ( sub_burned ) + { + fprintf( stderr, "Warning: Skipping subtitle track %d, can't have more than one track burnt in\n", track+1 ); + continue; + } + sub_burned = 1; + + // Mark as burn-in + sub_config.dest = RENDERSUB; + } + else + { + sub_config.dest = PASSTHRUSUB; + } + sub_config.force = force; + sub_config.default_track = def; + hb_subtitle_add( job, &sub_config, track ); } - token = strtok(NULL, ","); } } - if( i < num_audio_tracks && i == 1 ) + + if( srtfile ) { - /* We have exactly one name and more than one audio track. Use the same - * name for all tracks. */ - for ( ; i < num_audio_tracks; i++) + char * token; + int i; + hb_subtitle_config_t sub_config; + + for( i=0; srtfile[i] != NULL; i++ ) { - audio = hb_list_audio_config_item(job->list_audio, i); - audio->out.name = strdup(anames); - } - } - /* Audio Track Names */ + char *codeset = "L1"; + int64_t offset = 0; + char *lang = "und"; - if( size ) - { - job->vbitrate = hb_calc_bitrate( job, size ); - fprintf( stderr, "Calculated bitrate: %d kbps\n", - job->vbitrate ); - } + token = srtfile[i]; + if( srtcodeset && srtcodeset[i] ) + { + codeset = srtcodeset[i]; + } + if( srtoffset && srtoffset[i] ) + { + offset = strtoll( srtoffset[i], &srtoffset[i], 0 ); + } + if ( srtlang && srtlang[i] ) + { + lang = srtlang[i]; + } + sub_config.default_track = + ( srtdefault != -1 ) && ( srtdefault == i + 1 ); + sub_config.force = 0; + strncpy( sub_config.src_filename, srtfile[i], 255); + sub_config.src_filename[255] = 0; + strncpy( sub_config.src_codeset, codeset, 39); + sub_config.src_codeset[39] = 0; + sub_config.offset = offset; - if( sub ) - { - job->subtitle = sub - 1; + hb_srt_add( job, &sub_config, lang); + } } if( native_language ) { - job->native_language = strdup( native_language ); + char audio_lang[4]; + + audio = hb_list_audio_config_item(job->list_audio, 0); + + if( audio ) + { + strncpy( audio_lang, audio->lang.iso639_2, sizeof( audio_lang ) ); + + if( strncasecmp( native_language, audio_lang, + sizeof( audio_lang ) ) != 0 ) + { + /* + * Audio language is not the same as our native language. + * If we have any subtitles in our native language they + * should be selected here if they haven't already been. + */ + hb_subtitle_t *subtitle, *subtitle2 = NULL; + int matched_track = 0; + + for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + { + subtitle = hb_list_item( title->list_subtitle, i ); + matched_track = i; + if( strcmp( subtitle->iso639_2, native_language ) == 0 ) + { + /* + * Found the first matching subtitle in our + * native language. Is it already selected? + */ + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) + { + subtitle2 = hb_list_item( job->list_subtitle, i ); + + if( subtitle2->track == subtitle->track) { + /* + * Already selected + */ + break; + } + subtitle2 = NULL; + } + + if( subtitle2 == NULL ) + { + /* + * Not already selected, so select it. + */ + hb_subtitle_config_t sub_config; + + if( native_dub ) + { + fprintf( stderr, "Warning: no matching audio for native language - using subtitles instead.\n"); + } + sub_config = subtitle->config; + + if( mux == HB_MUX_MKV || subtitle->format == TEXTSUB) + { + sub_config.dest = PASSTHRUSUB; + } + + sub_config.force = 0; + sub_config.default_track = 1; + hb_subtitle_add( job, &sub_config, matched_track); + } + /* + * Stop searching. + */ + break; + } + } + } + } } if( job->mux ) @@ -1647,11 +2183,6 @@ static int HandleEvents( hb_handle_t * h ) job->file = strdup( output ); - if( crf ) - { - job->crf = 1; - } - if( color_matrix ) { job->color_matrix = color_matrix; @@ -1670,11 +2201,6 @@ static int HandleEvents( hb_handle_t * h ) if (maxHeight) job->maxHeight = maxHeight; - if( subtitle_force ) - { - job->subtitle_force = subtitle_force; - } - if( start_at_preview ) { job->start_at_preview = start_at_preview - 1; @@ -1693,6 +2219,18 @@ static int HandleEvents( hb_handle_t * h ) subtitle_scan = 0; } + if( start_at_pts ) + { + job->pts_to_start = start_at_pts; + subtitle_scan = 0; + } + + if( start_at_frame ) + { + job->frame_to_start = start_at_frame; + subtitle_scan = 0; + } + if( subtitle_scan ) { char *x264opts_tmp; @@ -1710,8 +2248,6 @@ static int HandleEvents( hb_handle_t * h ) job->indepth_scan = subtitle_scan; fprintf( stderr, "Subtitle Scan Enabled - enabling " "subtitles if found for foreign language segments\n"); - job->select_subtitle = malloc(sizeof(hb_subtitle_t*)); - *(job->select_subtitle) = NULL; /* * Add the pre-scan job @@ -1728,10 +2264,6 @@ static int HandleEvents( hb_handle_t * h ) * for the first pass and then off again for the * second. */ - hb_subtitle_t **subtitle_tmp = job->select_subtitle; - - job->select_subtitle = NULL; - job->pass = 1; job->indepth_scan = 0; @@ -1773,8 +2305,6 @@ static int HandleEvents( hb_handle_t * h ) } hb_add( h, job ); - job->select_subtitle = subtitle_tmp; - job->pass = 2; /* * On the second pass we turn off subtitle scan so that we @@ -1804,6 +2334,17 @@ static int HandleEvents( hb_handle_t * h ) } #define p s.param.working + case HB_STATE_SEARCHING: + fprintf( stdout, "\rEncoding: task %d of %d, Searching for start time, %.2f %%", + p.job_cur, p.job_count, 100.0 * p.progress ); + if( p.seconds > -1 ) + { + fprintf( stdout, " (ETA %02dh%02dm%02ds)", + p.hours, p.minutes, p.seconds ); + } + fflush(stdout); + break; + case HB_STATE_WORKING: fprintf( stdout, "\rEncoding: task %d of %d, %.2f %%", p.job_cur, p.job_count, 100.0 * p.progress ); @@ -1878,8 +2419,9 @@ void SigHandler( int i_signal ) static void ShowHelp() { int i; + FILE* const out = stdout; - fprintf( stderr, + fprintf( out, "Syntax: HandBrakeCLI [options] -i -o \n" "\n" "### General Handbrake Options------------------------------------------------\n\n" @@ -1891,27 +2433,33 @@ static void ShowHelp() " if the preset name has spaces, surround it with\n" " double quotation marks\n" " -z, --preset-list See a list of available built-in presets\n" + " --no-dvdnav Do not use dvdnav for reading DVDs\n" + " (experimental, enabled by default for testing)\n" "\n" "### Source Options-----------------------------------------------------------\n\n" " -i, --input Set input device\n" - " -t, --title Select a title to encode (0 to scan only,\n" + " -t, --title Select a title to encode (0 to scan all titles only,\n" " default: 1)\n" - " -L, --longest Select the longest title\n" + " --scan Scan selected title only.\n" + " --main-feature Detect and select the main feature title.\n" " -c, --chapters Select chapters (e.g. \"1-3\" for chapters\n" " 1 to 3, or \"3\" for chapter 3 only,\n" " default: all chapters)\n" + " --angle Select the DVD angle\n" " --previews <#:B> Select how many preview images are generated (max 30),\n" " and whether or not they're stored to disk (0 or 1).\n" " (default: 10:0)\n" " --start-at-preview <#> Start encoding at a given preview.\n" + " --start-at Start encoding at a given frame, duration (in seconds),\n" + " or pts (on a 90kHz clock)\n" " --stop-at Stop encoding at a given frame, duration (in seconds),\n" " or pts (on a 90kHz clock)" "\n" "### Destination Options------------------------------------------------------\n\n" " -o, --output Set output file name\n" - " -f, --format Set output format (avi/mp4/ogm/mkv, default:\n" + " -f, --format Set output format (mp4/mkv, default:\n" " autodetected from file name)\n" " -m, --markers Add chapter markers (mp4 and mkv output formats only)\n" " -4, --large-file Use 64-bit mp4 files that can hold more than\n" @@ -1922,13 +2470,12 @@ static void ShowHelp() "### Video Options------------------------------------------------------------\n\n" - " -e, --encoder Set video library encoder (ffmpeg,xvid,\n" - " x264,theora default: ffmpeg)\n" + " -e, --encoder Set video library encoder (ffmpeg,x264,theora)\n" + " (default: ffmpeg)\n" " -x, --x264opts Specify advanced x264 options in the\n" " same style as mencoder:\n" " option1=value1:option2=value2\n" - " -q, --quality Set video quality (0.0..1.0)\n" - " -Q, --cqp Use with -q for CQP instead of CRF\n" + " -q, --quality Set video quality\n" " -S, --size Set target size\n" " -b, --vb Set video bitrate (default: 1000)\n" " -2, --two-pass Use two-pass mode\n" @@ -1939,14 +2486,24 @@ static void ShowHelp() " -r, --rate Set video framerate (" ); for( i = 0; i < hb_video_rates_count; i++ ) { - fprintf( stderr, hb_video_rates[i].string ); + fprintf( out, hb_video_rates[i].string ); if( i != hb_video_rates_count - 1 ) - fprintf( stderr, "/" ); + fprintf( out, "/" ); } - fprintf( stderr, ")\n" + fprintf( out, ")\n" " Be aware that not specifying a framerate lets\n" " HandBrake preserve a source's time stamps,\n" " potentially creating variable framerate video\n" + " --vfr, --cfr, --pfr Select variable, constant or peak-limited\n" + " frame rate control. VFR preserves the source\n" + " timing. CFR makes the output constant rate at\n" + " the rate given by the -r flag (or the source's\n" + " average rate if no -r is given). PFR doesn't\n" + " allow the rate to go over the rate specified\n" + " with the -r flag but won't change the source\n" + " timing if it's below that rate.\n" + " If none of these flags are given, the default\n" + " is --cfr when -r is given and --vfr otherwise\n" "\n" "### Audio Options-----------------------------------------------------------\n\n" @@ -1954,24 +2511,41 @@ static void ShowHelp() " More than one output track can be used for one\n" " input.\n" " (\"none\" for no audio, \"1,2,3\" for multiple\n" - " tracks, default: first one)\n" - " -E, --aencoder Audio encoder(s) (faac/lame/vorbis/ac3) \n" - " ac3 meaning passthrough\n" + " tracks, default: first one)\n" ); + +#ifdef __APPLE_CC__ + fprintf( out, + " -E, --aencoder Audio encoder(s)\n" + " (ca_aac/faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\n" + " copy, copy:ac3 and copy:dts meaning passthrough.\n" + " copy will passthrough either ac3 or dts.\n" + " Separated by commas for more than one audio track.\n" + " (default: ca_aac)\n" ); +#else + fprintf( out, + " -E, --aencoder Audio encoder(s):\n" + " (faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\n" + " copy, copy:ac3 and copy:dts meaning passthrough.\n" + " copy will passthrough either ac3 or dts.\n" " Separated by commas for more than one audio track.\n" - " (default: guessed)\n" - " -B, --ab Set audio bitrate(s) (default: 160)\n" + " (default: faac for mp4, lame for mkv)\n" ); +#endif + fprintf( out, + " -B, --ab Set audio bitrate(s) (default: depends on the\n" + " selected codec, mixdown and samplerate)\n" " Separated by commas for more than one audio track.\n" " -6, --mixdown Format(s) for surround sound downmixing\n" " Separated by commas for more than one audio track.\n" - " (mono/stereo/dpl1/dpl2/6ch, default: dpl2)\n" + " (mono/stereo/dpl1/dpl2/6ch, default: up to 6ch for ac3,\n" + " up to dpl2 for other encoders)\n" " -R, --arate Set audio samplerate(s) (" ); for( i = 0; i < hb_audio_rates_count; i++ ) { - fprintf( stderr, hb_audio_rates[i].string ); + fprintf( out, hb_audio_rates[i].string ); if( i != hb_audio_rates_count - 1 ) - fprintf( stderr, "/" ); + fprintf( out, "/" ); } - fprintf( stderr, " kHz)\n" + fprintf( out, " kHz)\n" " Separated by commas for more than one audio track.\n" " -D, --drc Apply extra dynamic range compression to the audio,\n" " making soft sounds louder. Range is 1.0 to 4.0\n" @@ -1987,11 +2561,23 @@ static void ShowHelp() " --crop Set cropping values (default: autocrop)\n" " -Y, --maxHeight <#> Set maximum height\n" " -X, --maxWidth <#> Set maximum width\n" - " -p, --pixelratio Store pixel aspect ratio in video stream\n" - " -P, --loosePixelratio Store pixel aspect ratio with specified width\n" - " Takes as optional arguments what number you want\n" - " the dimensions to divide cleanly by (default 16)\n" - " and the pixel ratio to use (default autodetected)\n" + " --strict-anamorphic Store pixel aspect ratio in video stream\n" + " --loose-anamorphic Store pixel aspect ratio with specified width\n" + " --custom-anamorphic Store pixel aspect ratio in video stream and\n" + " directly control all parameters.\n" + " --display-width Set the width to scale the actual pixels to\n" + " at playback, for custom anamorphic.\n" + " --keep-display-aspect Preserve the source's display aspect ratio\n" + " when using custom anamorphic\n" + " --pixel-aspect Set a custom pixel aspect for custom anamorphic\n" + " \n" + " (--display-width and --pixel-aspect are mutually\n" + " exclusive and the former will override the latter)\n" + " --itu-par Use wider, ITU pixel aspect values for loose and\n" + " custom anamorphic, useful with underscanned sources\n" + " --modulus Set the number you want the scaled pixel dimensions\n" + " to divide cleanly by. Does not affect strict\n" + " anamorphic mode, which is always mod 2 (default: 16)\n" " -M --color-matrix Set the color space signaled by the output\n" " <601 or 709> (Bt.601 is mostly for SD content, Bt.709 for HD,\n" " default: set by resolution)\n" @@ -2004,37 +2590,82 @@ static void ShowHelp() " or\n" " \n" " -5, --decomb Selectively deinterlaces when it detects combing\n" - " (default: 1:2:6:9:80:16:16)\n" + " \n" + " (default: 7:2:6:9:80:16:16:10:20:20:4:2:50:24:1:-1)\n" " -9, --detelecine Detelecine (ivtc) video with pullup filter\n" " Note: this filter drops duplicate frames to\n" " restore the pre-telecine framerate, unless you\n" " specify a constant framerate (--rate 29.97)\n" - " (default 1:1:4:4:0:0)\n" + " (default 1:1:4:4:0:0:-1)\n" " -8, --denoise Denoise video with hqdn3d filter\n" " (default 4:3:6:4.5)\n" " or\n" " \n" " -7, --deblock Deblock video with pp7 filter\n" " (default 5:2)\n" + " --rotate Flips images axes\n" + " (default 3)\n" " -g, --grayscale Grayscale encoding\n" "\n" "### Subtitle Options------------------------------------------------------------\n\n" - " -s, --subtitle Select subtitle (default: none)\n" - " -U, --subtitle-scan Scan for subtitles in an extra 1st pass, and choose\n" - " the one that's only used 10 percent of the time\n" - " or less. This should locate subtitles for short\n" - " foreign language segments. Best used in conjunction\n" - " with --subtitle-forced.\n" + " -s, --subtitle Select subtitle track(s), separated by commas\n" + " More than one output track can be used for one\n" + " input.\n" + " Example: \"1,2,3\" for multiple tracks.\n" + " A special track name \"scan\" adds an extra 1st pass.\n" + " This extra pass scans subtitles matching the\n" + " language of the first audio or the language \n" + " selected by --native-language.\n" + " The one that's only used 10 percent of the time\n" + " or less is selected. This should locate subtitles\n" + " for short foreign language segments. Best used in\n" + " conjunction with --subtitle-forced.\n" " -F, --subtitle-forced Only display subtitles from the selected stream if\n" - " the subtitle has the forced flag set. May be used in\n" - " conjunction with --subtitle-scan to auto-select\n" - " a stream if it contains forced subtitles.\n" - " -N, --native-language Select subtitles with this language if it does not\n" - " match the Audio language. Provide the language's\n" - " iso639-2 code (fre, eng, spa, dut, et cetera)\n" - - + " the subtitle has the forced flag set. The values in\n" + " \"string\" are indexes into the subtitle list\n" + " specified with '--subtitle'.\n" + " Separated by commas for more than one audio track.\n" + " Example: \"1,2,3\" for multiple tracks.\n" + " If \"string\" is omitted, the first track is forced.\n" + " --subtitle-burn \"Burn\" the selected subtitle into the video track\n" + " If \"number\" is omitted, the first track is burned.\n" + " \"number\" is an index into the subtitle list\n" + " specified with '--subtitle'.\n" + " --subtitle-default Flag the selected subtitle as the default subtitle\n" + " to be displayed upon playback. Setting no default\n" + " means no subtitle will be automatically displayed\n" + " If \"number\" is omitted, the first track is default.\n" + " \"number\" is an index into the subtitle list\n" + " specified with '--subtitle'.\n" + " -N, --native-language Specifiy the your language preference. When the first\n" + " audio track does not match your native language then\n" + " select the first subtitle that does. When used in\n" + " conjunction with --native-dub the audio track is\n" + " changed in preference to subtitles. Provide the\n" + " language's iso639-2 code (fre, eng, spa, dut, et cetera)\n" + " --native-dub Used in conjunction with --native-language\n" + " requests that if no audio tracks are selected the\n" + " default selected audio track will be the first one\n" + " that matches the --native-language. If there are no\n" + " matching audio tracks then the first matching\n" + " subtitle track is used instead.\n" + " --srt-file SubRip SRT filename(s), separated by commas.\n" + " --srt-codeset Character codeset(s) that the SRT file(s) are\n" + " encoded in, separted by commas.\n" + " Use 'iconv -l' for a list of valid\n" + " codesets. If not specified latin1 is assumed\n" + " --srt-offset Offset in milli-seconds to apply to the SRT file(s)\n" + " separted by commas. If not specified zero is assumed.\n" + " Offsets may be negative.\n" + " --srt-lang Language as an iso639-2 code fra, eng, spa et cetera)\n" + " for the SRT file(s) separated by commas. If not specified\n" + " then 'und' is used.\n" + " --srt-default Flag the selected srt as the default subtitle\n" + " to be displayed upon playback. Setting no default\n" + " means no subtitle will be automatically displayed\n" + " If \"number\" is omitted, the first srt is default.\n" + " \"number\" is an 1 based index into the srt-file list\n" "\n" @@ -2046,60 +2677,94 @@ static void ShowHelp() ****************************************************************************/ static void ShowPresets() { - printf("\n< Apple\n"); - - printf("\n + Universal: -e x264 -q 0.589999973773956 -a 1,1 -E faac,ac3 -B 160,auto -R 48,Auto -6 dpl2,auto -f mp4 -X 720 -P -m -x level=30:cabac=0:ref=3:mixed-refs=1:analyse=all:me=umh:no-fast-pskip=1\n"); - - printf("\n + iPod: -e x264 -b 700 -a 1 -E faac -B 160 -R 48 -6 dpl2 -f mp4 -I -X 320 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1\n"); - - printf("\n + iPhone & iPod Touch: -e x264 -q 0.589999973773956 -a 1 -E faac -B 128 -R 48 -6 dpl2 -f mp4 -X 480 -m -x level=30:cabac=0:ref=2:mixed-refs:analyse=all:me=umh:no-fast-pskip=1\n"); - - printf("\n + AppleTV: -e x264 -q 0.589999973773956 -a 1,1 -E faac,ac3 -B 160,auto -R 48,Auto -6 dpl2,auto -f mp4 -4 -X 960 -P -m -x level=30:cabac=0:ref=3:mixed-refs=1:bframes=6:weightb=1:direct=auto:no-fast-pskip=1:me=umh:subq=7:analyse=all\n"); - - printf("\n + QuickTime: -e x264 -b 1800 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mp4 -p -m -2 -T -x ref=3:mixed-refs:bframes=3:weightb:direct=auto:me=umh:subme=7:analyse=all:8x8dct:trellis=1:no-fast-pskip=1:psy-rd=1,1\n"); - - printf("\n << Legacy\n"); - - printf("\n + AppleTV Legacy: -e x264 -b 2500 -a 1,1 -E faac,ac3 -B 160,auto -R 48,Auto -6 dpl2,auto -f mp4 -4 -p -m -x bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:trellis=1:cabac=0\n"); - - printf("\n + iPhone Legacy: -e x264 -b 960 -a 1 -E faac -B 128 -R 48 -6 dpl2 -f mp4 -I -X 480 -m -x level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:trellis=1\n"); - - printf("\n + iPod Legacy: -e x264 -b 1500 -a 1 -E faac -B 160 -R 48 -6 dpl2 -f mp4 -I -X 640 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1\n"); - - printf("\n >>\n"); - + fprintf( stderr, "%s - %s - %s\n", HB_PROJECT_TITLE, HB_PROJECT_BUILD_TITLE, HB_PROJECT_URL_WEBSITE ); + + printf("\n< Apple\n"); + + printf("\n + Universal: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -X 720 --loose-anamorphic -m -x cabac=0:ref=2:me=umh:bframes=0:weightp=0:8x8dct=0:trellis=0:subme=6\n"); + + printf("\n + iPod: -e x264 -b 700 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 320 -m -x level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:subme=6:8x8dct=0:trellis=0\n"); + + printf("\n + iPhone & iPod Touch: -e x264 -q 20.0 -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 -f mp4 -X 480 -m -x cabac=0:ref=2:me=umh:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0\n"); + + printf("\n + iPhone 4: -e x264 -q 20.0 -r 29.97 --pfr -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -4 -X 960 --loose-anamorphic -m\n"); + + printf("\n + iPad: -e x264 -q 20.0 -r 29.97 --pfr -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -4 -X 1024 --loose-anamorphic -m\n"); + + printf("\n + AppleTV: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 -X 960 --loose-anamorphic -m -x cabac=0:ref=2:me=umh:b-pyramid=none:b-adapt=2:weightb=0:trellis=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500\n"); + + printf("\n + AppleTV 2: -e x264 -q 20.0 -r 29.97 --pfr -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 -X 1280 --loose-anamorphic -m\n"); + printf("\n>\n"); - - printf("\n< Basic\n"); - - printf("\n + Normal: -e x264 -b 1500 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mp4 -p -m -2 -T -x ref=2:bframes=2:me=umh\n"); - - printf("\n + Classic: -b 1000 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mp4\n"); - + + printf("\n< Regular\n"); + + printf("\n + Normal: -e x264 -q 20.0 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 --strict-anamorphic -m -x ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0\n"); + + printf("\n + High Profile: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 --detelecine --decomb --loose-anamorphic -m -x b-adapt=2:rc-lookahead=50\n"); + + printf("\n>\n"); + + printf("\n< Legacy\n"); + + printf("\n + Classic: -b 1000 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4\n"); + + printf("\n + AppleTV Legacy: -e x264 -b 2500 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 --strict-anamorphic -m -x ref=1:b-pyramid=none:weightp=0:subme=5:me=umh:no-fast-pskip=1:cabac=0:weightb=0:8x8dct=0:trellis=0\n"); + + printf("\n + iPhone Legacy: -e x264 -b 960 -a 1 -E faac -B 128 -6 dpl2 -R Auto -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:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0\n"); + + printf("\n + iPod Legacy: -e x264 -b 1500 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 640 -m -x level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subme=6:8x8dct=0:trellis=0\n"); + printf("\n>\n"); - printf("\n< High Profile\n"); - - printf("\n + Animation: -e x264 -b 1000 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mkv --detelecine --decomb -p -m -2 -T -x ref=5:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip:filter=2,2:psy-rd=1,1:subme=9\n"); - - printf("\n + Constant Quality Rate: -e x264 -q 0.600000023841858 -a 1 -E ac3 -B 160 -R Auto -6 auto -f mkv -p -m -x ref=3:mixed-refs:bframes=3:b-pyramid:weightb:filter=-2,-1:trellis=1:analyse=all:8x8dct:me=umh:subme=9:psy-rd=1,1\n"); - - printf("\n + Film: -e x264 -b 1800 -a 1 -E ac3 -B 160 -R Auto -6 auto -f mkv -p -m -2 -T -x ref=3:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:subme=9:analyse=all:8x8dct:trellis=1:no-fast-pskip:psy-rd=1,1\n"); +} - printf("\n + Television: -e x264 -b 1300 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mkv --detelecine --decomb -p -m -2 -T -x ref=3:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:subme=9:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip=1:psy-rd=1,1\n"); +static char * hb_strndup( char * str, int len ) +{ + char * res; + int str_len = strlen( str ); - printf("\n>\n"); + res = malloc( len > str_len ? str_len + 1 : len + 1 ); + strncpy( res, str, len ); + res[len] = '\0'; + return res; +} - printf("\n< Gaming Consoles\n"); +static char** str_split( char *str, char delem ) +{ + char * pos; + char * end; + char ** ret; + int count, i; - printf("\n + PSP: -b 1024 -a 1 -E faac -B 128 -R 48 -6 dpl2 -f mp4 -X 368 -Y 208 -m\n"); + if ( str == NULL || str[0] == 0 ) + { + ret = malloc( sizeof(char*) ); + *ret = NULL; + return ret; + } - printf("\n + PS3: -e x264 -b 2500 -a 1 -E faac -B 160 -R 48 -6 dpl2 -f mp4 --crop 0:0:0:0 -p -x level=41:me=umh\n"); + // Find number of elements in the string + count = 1; + pos = str; + while ( ( pos = strchr( pos, delem ) ) != NULL ) + { + count++; + pos++; + } - printf("\n + Xbox 360: -e x264 -b 2000 -a 1 -E faac -B 160 -R 48 -6 dpl2 -f mp4 -p -x level=40:ref=2:mixed-refs:bframes=3:weightb:subme=9:direct=auto:b-pyramid:me=umh:analyse=all:no-fast-pskip:filter=-2,-1\n"); + ret = calloc( ( count + 1 ), sizeof(char*) ); - printf("\n>\n"); + pos = str; + for ( i = 0; i < count - 1; i++ ) + { + end = strchr( pos, delem ); + ret[i] = hb_strndup(pos, end - pos); + pos = end + 1; + } + ret[i] = strdup(pos); + return ret; } /**************************************************************************** @@ -2108,9 +2773,28 @@ static void ShowPresets() static int ParseOptions( int argc, char ** argv ) { - #define PREVIEWS 257 - #define START_AT_PREVIEW 258 - #define STOP_AT 259 + #define PREVIEWS 257 + #define START_AT_PREVIEW 258 + #define START_AT 259 + #define STOP_AT 260 + #define ANGLE 261 + #define DVDNAV 262 + #define DISPLAY_WIDTH 263 + #define PIXEL_ASPECT 264 + #define MODULUS 265 + #define KEEP_DISPLAY_ASPECT 266 + #define SUB_BURNED 267 + #define SUB_DEFAULT 268 + #define NATIVE_DUB 269 + #define SRT_FILE 270 + #define SRT_CODESET 271 + #define SRT_OFFSET 272 + #define SRT_LANG 273 + #define SRT_DEFAULT 274 + #define ROTATE_FILTER 275 + #define SCAN_ONLY 276 + #define MAIN_FEATURE 277 + #define MIN_DURATION 278 for( ;; ) { @@ -2120,6 +2804,7 @@ static int ParseOptions( int argc, char ** argv ) { "update", no_argument, NULL, 'u' }, { "verbose", optional_argument, NULL, 'v' }, { "cpu", required_argument, NULL, 'C' }, + { "no-dvdnav", no_argument, NULL, DVDNAV }, { "format", required_argument, NULL, 'f' }, { "input", required_argument, NULL, 'i' }, @@ -2129,17 +2814,26 @@ static int ParseOptions( int argc, char ** argv ) { "ipod-atom", no_argument, NULL, 'I' }, { "title", required_argument, NULL, 't' }, - { "longest", no_argument, NULL, 'L' }, + { "min-duration",required_argument, NULL, MIN_DURATION }, + { "scan", no_argument, NULL, SCAN_ONLY }, + { "main-feature",no_argument, NULL, MAIN_FEATURE }, { "chapters", required_argument, NULL, 'c' }, + { "angle", required_argument, NULL, ANGLE }, { "markers", optional_argument, NULL, 'm' }, { "audio", required_argument, NULL, 'a' }, { "mixdown", required_argument, NULL, '6' }, { "drc", required_argument, NULL, 'D' }, { "subtitle", required_argument, NULL, 's' }, - { "subtitle-scan", no_argument, NULL, 'U' }, - { "subtitle-forced", no_argument, NULL, 'F' }, + { "subtitle-forced", optional_argument, NULL, 'F' }, + { "subtitle-burned", optional_argument, NULL, SUB_BURNED }, + { "subtitle-default", optional_argument, NULL, SUB_DEFAULT }, + { "srt-file", required_argument, NULL, SRT_FILE }, + { "srt-codeset", required_argument, NULL, SRT_CODESET }, + { "srt-offset", required_argument, NULL, SRT_OFFSET }, + { "srt-lang", required_argument, NULL, SRT_LANG }, + { "srt-default", optional_argument, NULL, SRT_DEFAULT }, { "native-language", required_argument, NULL,'N' }, - + { "native-dub", no_argument, NULL, NATIVE_DUB }, { "encoder", required_argument, NULL, 'e' }, { "aencoder", required_argument, NULL, 'E' }, { "two-pass", no_argument, NULL, '2' }, @@ -2149,8 +2843,15 @@ static int ParseOptions( int argc, char ** argv ) { "detelecine", optional_argument, NULL, '9' }, { "decomb", optional_argument, NULL, '5' }, { "grayscale", no_argument, NULL, 'g' }, - { "pixelratio", no_argument, NULL, 'p' }, - { "loosePixelratio", optional_argument, NULL, 'P' }, + { "rotate", optional_argument, NULL, ROTATE_FILTER }, + { "strict-anamorphic", no_argument, &anamorphic_mode, 1 }, + { "loose-anamorphic", no_argument, &anamorphic_mode, 2 }, + { "custom-anamorphic", no_argument, &anamorphic_mode, 3 }, + { "display-width", required_argument, NULL, DISPLAY_WIDTH }, + { "keep-display-aspect", no_argument, &keep_display_aspect, 1 }, + { "pixel-aspect", required_argument, NULL, PIXEL_ASPECT }, + { "modulus", required_argument, NULL, MODULUS }, + { "itu-par", no_argument, &itu_par, 1 }, { "width", required_argument, NULL, 'w' }, { "height", required_argument, NULL, 'l' }, { "crop", required_argument, NULL, 'n' }, @@ -2161,7 +2862,6 @@ static int ParseOptions( int argc, char ** argv ) { "ab", required_argument, NULL, 'B' }, { "rate", required_argument, NULL, 'r' }, { "arate", required_argument, NULL, 'R' }, - { "cqp", no_argument, NULL, 'Q' }, { "x264opts", required_argument, NULL, 'x' }, { "turbo", no_argument, NULL, 'T' }, { "maxHeight", required_argument, NULL, 'Y' }, @@ -2173,16 +2873,25 @@ static int ParseOptions( int argc, char ** argv ) { "color-matrix",required_argument, NULL, 'M' }, { "previews", required_argument, NULL, PREVIEWS }, { "start-at-preview", required_argument, NULL, START_AT_PREVIEW }, + { "start-at", required_argument, NULL, START_AT }, { "stop-at", required_argument, NULL, STOP_AT }, - + { "vfr", no_argument, &cfr, 0 }, + { "cfr", no_argument, &cfr, 1 }, + { "pfr", no_argument, &cfr, 2 }, +#if defined( __APPLE_CC__ ) + { "no-vlc-dylib-path", no_argument, &no_vlc_dylib, 1 }, +#endif { 0, 0, 0, 0 } }; int option_index = 0; int c; + int cur_optind; - c = getopt_long( argc, argv, - "hv::uC:f:4i:Io:t:Lc:m::M:a:A:6:s:UFN:e:E:2dD:7895gpOP::w:l:n:b:q:S:B:r:R:Qx:TY:X:Z:z", + cur_optind = optind; + c = getopt_long( argc, argv, + "hv::uC:f:4i:Io:t:c:m::M:a:A:6:s:UF::N:e:E:" + "2dD:7895gOw:l:n:b:q:S:B:r:R:x:TY:X:Z:z", long_options, &option_index ); if( c < 0 ) { @@ -2191,6 +2900,9 @@ static int ParseOptions( int argc, char ** argv ) switch( c ) { + case 0: + /* option was handled entirely in getopt_long */ + break; case 'h': ShowHelp(); exit( 0 ); @@ -2218,6 +2930,9 @@ static int ParseOptions( int argc, char ** argv ) case 'z': ShowPresets(); exit ( 0 ); + case DVDNAV: + dvdnav = 0; + break; case 'f': format = strdup( optarg ); @@ -2254,8 +2969,11 @@ static int ParseOptions( int argc, char ** argv ) case 't': titleindex = atoi( optarg ); break; - case 'L': - longest_title = 1; + case SCAN_ONLY: + titlescan = 1; + break; + case MAIN_FEATURE: + main_feature = 1; break; case 'c': { @@ -2278,6 +2996,9 @@ static int ParseOptions( int argc, char ** argv ) } break; } + case ANGLE: + angle = atoi( optarg ); + break; case 'm': if( optarg != NULL ) { @@ -2289,6 +3010,7 @@ static int ParseOptions( int argc, char ** argv ) if( optarg != NULL ) { atracks = strdup( optarg ); + audio_explicit = 1; } else { @@ -2308,17 +3030,59 @@ static int ParseOptions( int argc, char ** argv ) } break; case 's': - sub = atoi( optarg ); - break; - case 'U': - subtitle_scan = 1; + subtracks = str_split( optarg, ',' ); break; case 'F': - subtitle_force = 1; + subforce = str_split( optarg, ',' ); + break; + case SUB_BURNED: + if( optarg != NULL ) + { + subburn = strdup( optarg ); + } + else + { + subburn = "" ; + } + break; + case SUB_DEFAULT: + if( optarg != NULL ) + { + subdefault = strdup( optarg ); + } + else + { + subdefault = "" ; + } break; case 'N': native_language = strdup( optarg ); break; + case NATIVE_DUB: + native_dub = 1; + break; + case SRT_FILE: + srtfile = str_split( optarg, ',' ); + break; + case SRT_CODESET: + srtcodeset = str_split( optarg, ',' ); + break; + case SRT_OFFSET: + srtoffset = str_split( optarg, ',' ); + break; + case SRT_LANG: + srtlang = str_split( optarg, ',' ); + break; + case SRT_DEFAULT: + if( optarg != NULL ) + { + srtdefault = atoi( optarg ); + } + else + { + srtdefault = 1 ; + } + break; case '2': twoPass = 1; break; @@ -2390,38 +3154,39 @@ static int ParseOptions( int argc, char ** argv ) case 'g': grayscale = 1; break; - case 'p': - pixelratio = 1; - break; - case 'P': - loosePixelratio = 1; + case ROTATE_FILTER: if( optarg != NULL ) { - sscanf( optarg, "%i:%i:%i", &modulus, &par_width, &par_height ); + rotate_opt = strdup( optarg ); } + rotate = 1; break; - case 'e': - if( !strcasecmp( optarg, "ffmpeg" ) ) + case DISPLAY_WIDTH: + if( optarg != NULL ) { - vcodec = HB_VCODEC_FFMPEG; + sscanf( optarg, "%i", &display_width ); } - else if( !strcasecmp( optarg, "xvid" ) ) + break; + case PIXEL_ASPECT: + if( optarg != NULL ) { - vcodec = HB_VCODEC_XVID; + sscanf( optarg, "%i:%i", &par_width, &par_height ); } - else if( !strcasecmp( optarg, "x264" ) ) + break; + case MODULUS: + if( optarg != NULL ) { - vcodec = HB_VCODEC_X264; + sscanf( optarg, "%i", &modulus ); } - else if( !strcasecmp( optarg, "x264b13" ) ) + break; + case 'e': + if( !strcasecmp( optarg, "ffmpeg" ) ) { - vcodec = HB_VCODEC_X264; - h264_13 = 1; + vcodec = HB_VCODEC_FFMPEG; } - else if( !strcasecmp( optarg, "x264b30" ) ) + else if( !strcasecmp( optarg, "x264" ) ) { vcodec = HB_VCODEC_X264; - h264_30 = 1; } else if( !strcasecmp( optarg, "theora" ) ) { @@ -2474,6 +3239,10 @@ static int ParseOptions( int argc, char ** argv ) { fprintf( stderr, "invalid framerate %s\n", optarg ); } + else if ( cfr == 0 ) + { + cfr = 1; + } break; } case 'R': @@ -2497,9 +3266,6 @@ static int ParseOptions( int argc, char ** argv ) abitrates = strdup( optarg ); } break; - case 'Q': - crf = 0; - break; case 'x': x264opts = strdup( optarg ); break; @@ -2524,6 +3290,26 @@ static int ParseOptions( int argc, char ** argv ) case START_AT_PREVIEW: start_at_preview = atoi( optarg ); break; + case START_AT: + start_at_string = strdup( optarg ); + start_at_token = strtok( start_at_string, ":"); + if( !strcmp( start_at_token, "frame" ) ) + { + start_at_token = strtok( NULL, ":"); + start_at_frame = atoi(start_at_token); + } + else if( !strcmp( start_at_token, "pts" ) ) + { + start_at_token = strtok( NULL, ":"); + sscanf( start_at_token, "%"SCNd64, &start_at_pts ); + } + else if( !strcmp( start_at_token, "duration" ) ) + { + start_at_token = strtok( NULL, ":"); + sscanf( start_at_token, "%"SCNd64, &start_at_pts ); + start_at_pts *= 90000LL; + } + break; case STOP_AT: stop_at_string = strdup( optarg ); stop_at_token = strtok( stop_at_string, ":"); @@ -2550,8 +3336,11 @@ static int ParseOptions( int argc, char ** argv ) else if( atoi( optarg ) == 709 ) color_matrix = 2; break; + case MIN_DURATION: + min_title_duration = strtol( optarg, NULL, 0 ); + break; default: - fprintf( stderr, "unknown option (%s)\n", argv[optind] ); + fprintf( stderr, "unknown option (%s)\n", argv[cur_optind] ); return -1; } } @@ -2559,8 +3348,109 @@ static int ParseOptions( int argc, char ** argv ) return 0; } +char * str_printf(const char *fmt, ...) +{ + /* Guess we need no more than 100 bytes. */ + int len; + va_list ap; + int size = 100; + char *tmp, *str = NULL; + + str = (char*)malloc(size); + while (1) + { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + len = vsnprintf(str, size, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (len > -1 && len < size) { + return str; + } + + /* Else try again with more space. */ + if (len > -1) /* glibc 2.1 */ + size = len+1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + + tmp = (char*)realloc(str, size); + if (tmp == NULL) { + return str; + } + str = tmp; + } +} + static int CheckOptions( int argc, char ** argv ) { +#if defined( __APPLE_CC__ ) + // If OSX, add VLC dylib path and exec to make it stick. + char *dylib_path; + + if ( !no_vlc_dylib ) + { + dylib_path = getenv("DYLD_FALLBACK_LIBRARY_PATH"); + if ( dylib_path == NULL || + strstr( dylib_path, "/Applications/VLC.app/Contents/MacOS/lib" ) == NULL ) + { + char *path = NULL; + char *home; + int result = -1; + + home = getenv("HOME"); + + if ( dylib_path == NULL ) + { + // Set the system default of $HOME/lib:/usr/local/lib:/usr/lib + // And add our extra path + if ( home != NULL ) + { + path = str_printf("%s/lib:%s:%s:%s%s", home, + DEFAULT_DYLD_PATH, + EXTRA_VLC_DYLD_PATH, + home, EXTRA_VLC_DYLD_PATH); + } + else + { + path = str_printf("%s:%s", DEFAULT_DYLD_PATH, EXTRA_VLC_DYLD_PATH); + } + if ( path != NULL ) + result = setenv("DYLD_FALLBACK_LIBRARY_PATH", path, 1); + } + else + { + // add our extra path + if ( home != NULL ) + { + path = str_printf("%s:%s:%s%s", dylib_path, EXTRA_VLC_DYLD_PATH, + home, EXTRA_VLC_DYLD_PATH); + } + else + { + path = str_printf("%s:%s", dylib_path, EXTRA_VLC_DYLD_PATH); + } + if ( path != NULL ) + result = setenv("DYLD_FALLBACK_LIBRARY_PATH", path, 1); + } + if ( result == 0 ) + { + const char ** new_argv; + int i; + + new_argv = (const char**)malloc( (argc + 2) * sizeof(char*) ); + new_argv[0] = argv[0]; + new_argv[1] = "--no-vlc-dylib-path"; + for (i = 1; i < argc; i++) + new_argv[i+1] = argv[i]; + new_argv[i+1] = NULL; + execv(new_argv[0], (char* const*)new_argv); + } + } + } +#endif + if( update ) { return 0; @@ -2574,7 +3464,7 @@ static int CheckOptions( int argc, char ** argv ) } /* Parse format */ - if( titleindex > 0 ) + if( titleindex > 0 && !titlescan ) { if( output == NULL || *output == '\0' ) { @@ -2588,30 +3478,18 @@ static int CheckOptions( int argc, char ** argv ) char * p = strrchr( output, '.' ); /* autodetect */ - if( p && !strcasecmp( p, ".avi" ) ) - { - mux = HB_MUX_AVI; - default_acodec = HB_ACODEC_LAME; - } - else if( p && ( !strcasecmp( p, ".mp4" ) || - !strcasecmp( p, ".m4v" ) ) ) - { - if ( h264_30 == 1 ) - mux = HB_MUX_IPOD; - else - mux = HB_MUX_MP4; - default_acodec = HB_ACODEC_FAAC; - } - else if( p && ( !strcasecmp( p, ".ogm" ) || - !strcasecmp( p, ".ogg" ) ) ) + if( p && ( !strcasecmp( p, ".mp4" ) || + !strcasecmp( p, ".m4v" ) ) ) { - mux = HB_MUX_OGM; - default_acodec = HB_ACODEC_VORBIS; + mux = HB_MUX_MP4; } else if( p && !strcasecmp(p, ".mkv" ) ) { mux = HB_MUX_MKV; - default_acodec = HB_ACODEC_AC3; +#ifndef __APPLE_CC__ + // default to Lame for MKV (except under OS X where Core Audio is available) + default_acodec = HB_ACODEC_LAME; +#endif } else { @@ -2620,35 +3498,23 @@ static int CheckOptions( int argc, char ** argv ) return 0; } } - else if( !strcasecmp( format, "avi" ) ) - { - mux = HB_MUX_AVI; - default_acodec = HB_ACODEC_LAME; - } else if( !strcasecmp( format, "mp4" ) || !strcasecmp( format, "m4v" ) ) { - if ( h264_30 == 1) - mux = HB_MUX_IPOD; - else - mux = HB_MUX_MP4; - default_acodec = HB_ACODEC_FAAC; - } - else if( !strcasecmp( format, "ogm" ) || - !strcasecmp( format, "ogg" ) ) - { - mux = HB_MUX_OGM; - default_acodec = HB_ACODEC_VORBIS; + mux = HB_MUX_MP4; } else if( !strcasecmp( format, "mkv" ) ) { mux = HB_MUX_MKV; - default_acodec = HB_ACODEC_AC3; +#ifndef __APPLE_CC__ + // default to Lame for MKV (except under OS X where Core Audio is available) + default_acodec = HB_ACODEC_LAME; +#endif } else { fprintf( stderr, "Invalid output format (%s). Possible " - "choices are avi, mp4, m4v, ogm, ogg and mkv\n.", format ); + "choices are mp4, m4v and mkv\n.", format ); return 1; } } @@ -2662,9 +3528,17 @@ static int get_acodec_for_string( char *codec ) { return HB_ACODEC_AC3; } - else if( !strcasecmp( codec, "dts" ) || !strcasecmp( codec, "dca" ) ) + else if( !strcasecmp( codec, "copy" ) ) + { + return HB_ACODEC_AC3_PASS | HB_ACODEC_DCA_PASS; + } + else if( !strcasecmp( codec, "copy:ac3" ) ) + { + return HB_ACODEC_AC3_PASS; + } + else if( !strcasecmp( codec, "copy:dts" ) || !strcasecmp( codec, "copy:dca" ) ) { - return HB_ACODEC_DCA; + return HB_ACODEC_DCA_PASS; } else if( !strcasecmp( codec, "lame" ) ) { @@ -2678,6 +3552,12 @@ static int get_acodec_for_string( char *codec ) { return HB_ACODEC_VORBIS; } +#ifdef __APPLE__ + else if( !strcasecmp( codec, "ca_aac") ) + { + return HB_ACODEC_CA_AAC; + } +#endif else { return -1; @@ -2840,7 +3720,7 @@ static int is_dvd_service( io_service_t service ) * The whole media object is indicated in the IORegistry by the presence of a * property with the key "Whole" and value "Yes". ****************************************************************************/ -static is_whole_media_service( io_service_t service ) +static int is_whole_media_service( io_service_t service ) { int result = 0;