X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=test%2Ftest.c;h=c75482f0cbaffc5b663ad16d9c46df776ad6f54e;hb=91808a1f62713db501fada2de3ba4fcabfff0b7a;hp=b04886b2cc67f1b3285f2092fae3836a1dd6a695;hpb=9f4d5a6d490a89a6112a9235739e5b72a76cd68d;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/test/test.c b/test/test.c index b04886b2..c75482f0 100644 --- a/test/test.c +++ b/test/test.c @@ -11,14 +11,18 @@ #include #include -#ifdef PTW32_STATIC_LIB +#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 @@ -26,15 +30,16 @@ #endif /* Options */ -static int debug = HB_DEBUG_NONE; +static int debug = HB_DEBUG_ALL; static int update = 0; -static int dvdnav = 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 char * native_language = NULL; +static int native_dub = 0; static int twoPass = 0; static int deinterlace = 0; static char * deinterlace_opt = 0; @@ -62,10 +67,16 @@ static char * acodecs = NULL; static char * anames = NULL; static int default_acodec = HB_ACODEC_FAAC; static int default_abitrate = 160; -static char * subtracks = NULL; -static char * subforce = NULL; +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; @@ -88,7 +99,6 @@ 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; @@ -131,7 +141,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 */ @@ -171,7 +181,7 @@ int main( int argc, char ** argv ) return 1; } -#ifdef PTW32_STATIC_LIB +#if defined( PTW32_STATIC_LIB ) pthread_win32_process_attach_np(); pthread_win32_thread_attach_np(); #endif @@ -233,7 +243,29 @@ int main( int argc, char ** argv ) /* Wait... */ while( !die ) { -#if !defined(SYS_BEOS) && !defined(__MINGW32__) +#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; @@ -322,7 +354,7 @@ int main( int argc, char ** argv ) fprintf( stderr, "HandBrake has exited.\n" ); -#ifdef PTW32_STATIC_LIB +#if defined( PTW32_STATIC_LIB ) pthread_win32_thread_detach_np(); pthread_win32_process_detach_np(); #endif @@ -342,7 +374,6 @@ 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; @@ -378,12 +409,19 @@ 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" ); @@ -404,44 +442,24 @@ static void PrintTitleInfo( hb_title_t * title ) } -static int search_csv( const char * list, char * needle ) +static int test_sub_list( char ** list, char * needle, int pos ) { - char * token; - char * copy_list; - int pos = 1; + int i; if ( list == NULL || needle == NULL ) return 0; - copy_list = strdup( list ); - token = strtok(copy_list, ","); - if (token == NULL) - token = copy_list; - while( token != NULL ) + if ( list[0] == NULL && pos == 1 ) + return 1; + + for ( i = 0; list[i] != NULL; i++ ) { - if( !strcasecmp(token, needle ) ) - { - free( copy_list ); - return pos; - } - pos++; - token = strtok(NULL, ","); + if ( strcasecmp( list[i], needle ) == 0 ) + return i + 1; } - free( copy_list ); return 0; } -static int test_sub_list( const char * list, char * needle, int pos ) -{ - if ( list == NULL || needle == NULL ) - return 0; - - if ( list[0] == '\0' && pos == 1 ) - return 1; - - return search_csv( list, needle ); -} - static int HandleEvents( hb_handle_t * h ) { hb_state_t s; @@ -572,7 +590,6 @@ static int HandleEvents( hb_handle_t * h ) } vcodec = HB_VCODEC_X264; job->vquality = 20.0; - job->crf = 1; if( !atracks ) { atracks = strdup("1,1"); @@ -600,7 +617,7 @@ static int HandleEvents( hb_handle_t * h ) maxWidth = 720; if( !x264opts ) { - x264opts = strdup("cabac=0:ref=2:mixed-refs=1:me=umh"); + x264opts = strdup("cabac=0:ref=2:me=umh:bframes=0:8x8dct=0:trellis=0:subme=6"); } anamorphic_mode = 2; job->chapter_markers = 1; @@ -642,7 +659,7 @@ static int HandleEvents( hb_handle_t * h ) 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"); + x264opts = strdup("level=30:bframes=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; } @@ -655,7 +672,6 @@ static int HandleEvents( hb_handle_t * h ) } vcodec = HB_VCODEC_X264; job->vquality = 20.0; - job->crf = 1; if( !atracks ) { atracks = strdup("1"); @@ -683,7 +699,7 @@ static int HandleEvents( hb_handle_t * h ) maxWidth = 480; if( !x264opts ) { - x264opts = strdup("cabac=0:ref=2:mixed-refs:me=umh"); + x264opts = strdup("cabac=0:ref=2:me=umh:bframes=0:subme=6:8x8dct=0:trellis=0"); } job->chapter_markers = 1; } @@ -697,7 +713,6 @@ static int HandleEvents( hb_handle_t * h ) job->largeFileSize = 1; vcodec = HB_VCODEC_X264; job->vquality = 20.0; - job->crf = 1; if( !atracks ) { atracks = strdup("1,1"); @@ -725,7 +740,7 @@ static int HandleEvents( hb_handle_t * h ) maxWidth = 960; if( !x264opts ) { - x264opts = strdup("cabac=0:ref=2:mixed-refs=1:bframes=3:me=umh:subme=7:b-adapt=2:8x8dct=1"); + x264opts = strdup("cabac=0:ref=2:me=umh:b-adapt=2:weightb=0:trellis=0"); } anamorphic_mode = 2; job->chapter_markers = 1; @@ -739,7 +754,6 @@ static int HandleEvents( hb_handle_t * h ) } vcodec = HB_VCODEC_X264; job->vquality = 20.0; - job->crf = 1; if( !atracks ) { atracks = strdup("1"); @@ -766,7 +780,7 @@ static int HandleEvents( hb_handle_t * h ) } if( !x264opts ) { - x264opts = strdup("ref=2:bframes=2:me=umh"); + x264opts = strdup("ref=2:bframes=2:me=umh:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0"); } anamorphic_mode = 1; job->chapter_markers = 1; @@ -780,7 +794,6 @@ static int HandleEvents( hb_handle_t * h ) } vcodec = HB_VCODEC_X264; job->vquality = 20.0; - job->crf = 1; if( !atracks ) { atracks = strdup("1,1"); @@ -807,7 +820,7 @@ static int HandleEvents( hb_handle_t * h ) } if( !x264opts ) { - x264opts = strdup("ref=3:mixed-refs:bframes=3:weightb:b-pyramid:b-adapt=2:me=umh:subme=9:analyse=all:8x8dct"); + x264opts = strdup("b-pyramid:b-adapt=2:me=umh:subme=9:analyse=all:trellis=0"); } detelecine = 1; decomb = 1; @@ -883,7 +896,7 @@ static int HandleEvents( hb_handle_t * h ) } if( !x264opts ) { - x264opts = strdup("bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:cabac=0"); + x264opts = strdup("ref=1:subme=5:me=umh:no-fast-pskip=1:cabac=0:weightb=0:8x8dct=0:trellis=0"); } anamorphic_mode = 1; job->chapter_markers = 1; @@ -925,7 +938,7 @@ static int HandleEvents( hb_handle_t * h ) maxWidth = 480; if( !x264opts ) { - x264opts = strdup("level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0"); + x264opts = strdup("level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:bframes=0:subme=6:8x8dct=0:trellis=0"); } job->chapter_markers = 1; } @@ -966,7 +979,7 @@ static int HandleEvents( hb_handle_t * h ) maxWidth = 640; if( !x264opts ) { - 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"); + 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:subme=6:8x8dct=0:trellis=0"); } job->chapter_markers = 1; } @@ -1313,8 +1326,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); @@ -1630,63 +1694,79 @@ static int HandleEvents( hb_handle_t * h ) if( subtracks ) { - int pos; - - pos = search_csv(subtracks, "scan"); - if ( pos ) - { - int burn, force, def; - - burn = test_sub_list(subburn, "scan", pos); - force = test_sub_list(subforce, "scan", pos); - def = test_sub_list(subdefault, "scan", pos); - - if ( !burn && mux == HB_MUX_MKV ) - { - job->select_subtitle_config.dest = PASSTHRUSUB; - } - if ( !( !burn && mux == HB_MUX_MP4 ) ) - { - job->select_subtitle_config.force = force; - job->select_subtitle_config.default_track = def; - subtitle_scan = 1; - sub_burned = burn; - } - } + char * token; + int i, pos; - char * save; - char * token = strtok_r(subtracks, ",", &save); - if (token == NULL) - token = subtracks; pos = 0; - while( token != NULL ) + for ( i = 0; subtracks[i] != NULL; i++ ) { pos++; - if( !strcasecmp(token, "scan" ) ) + token = subtracks[i]; + if( strcasecmp(token, "scan" ) == 0 ) { - token = strtok_r(NULL, ",", &save); - continue; + int burn = 0, force = 0, def = 0; + + if ( subburn != NULL ) + { + burn = ( pos == 1 && subburn[0] == 0 ) || + ( strcmp( "scan", subburn ) == 0 ); + } + if ( subdefault != NULL ) + { + def = ( pos == 1 && subdefault[0] == 0 ) || + ( strcmp( "scan", subdefault ) == 0 ); + } + force = test_sub_list( subforce, "scan", pos ); + + if ( !burn && mux == HB_MUX_MKV ) + { + job->select_subtitle_config.dest = PASSTHRUSUB; + } + else if ( burn ) + { + if ( sub_burned ) + { + continue; + } + sub_burned = 1; + } + if ( !( !burn && mux == HB_MUX_MP4 ) ) + { + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; + subtitle_scan = 1; + } else { + fprintf( stderr, "Warning: Subtitle Scan for MP4 requires the '--subtitle-burn' option to be selected\n"); + } } else { hb_subtitle_t * subtitle; hb_subtitle_config_t sub_config; int track; - int burn, force, def; + int burn = 0, force = 0, def = 0; track = atoi(token) - 1; subtitle = hb_list_item(title->list_subtitle, track); if( subtitle == NULL ) { - fprintf( stderr, "Could not find subtitle track %d, skipped\n", track ); - token = strtok_r(NULL, ",", &save); + fprintf( stderr, "Warning: Could not find subtitle track %d, skipped\n", track+1 ); continue; } sub_config = subtitle->config; - burn = test_sub_list(subburn, token, pos); + if ( subburn != NULL ) + { + burn = ( pos == 1 && subburn[0] == 0 ) || + ( strcmp( token, subburn ) == 0 ); + } + if ( subdefault != NULL ) + { + def = ( pos == 1 && subdefault[0] == 0 ) || + ( strcmp( token, subdefault ) == 0 ); + } + force = test_sub_list(subforce, token, pos); - def = test_sub_list(subdefault, token, pos); if ( !burn && mux == HB_MUX_MKV && subtitle->format == PICTURESUB) @@ -1697,7 +1777,7 @@ static int HandleEvents( hb_handle_t * h ) subtitle->format == PICTURESUB) { // Skip any non-burned vobsubs when output is mp4 - token = strtok_r(NULL, ",", &save); + fprintf( stderr, "Warning: Skipping subtitle track %d, can't pass-through VOBSUBs in an MP4 container,\nadd '--subtitle-burn %d' to the command line\n", track+1, track+1 ); continue; } else if ( burn && subtitle->format == PICTURESUB ) @@ -1705,33 +1785,129 @@ static int HandleEvents( hb_handle_t * h ) // Only allow one subtitle to be burned into video if ( sub_burned ) { - token = strtok_r(NULL, ",", &save); + fprintf( stderr, "Warning: Skipping subtitle track %d, can't have more than one track burnt in\n", track+1 ); continue; } sub_burned = 1; } - sub_config.force = force; sub_config.default_track = def; hb_subtitle_add( job, &sub_config, track ); } - token = strtok_r(NULL, ",", &save); } } - if( native_language ) + if( srtfile ) { - job->native_language = strdup( native_language ); - if ( subtracks == NULL ) + char * token; + int i, pos; + hb_subtitle_config_t sub_config; + + pos = 0; + for( i=0; srtfile[i] != NULL; i++ ) { - if ( subforce ) - job->select_subtitle_config.force = 1; + char *codeset = "L1"; + int64_t offset = 0; + char *lang = "und"; + + pos++; + 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], 128); + strncpy( sub_config.src_codeset, codeset, 40); + sub_config.offset = offset; - if ( subburn == NULL && mux != HB_MUX_MP4 ) - job->select_subtitle_config.force = 1; + hb_srt_add( job, &sub_config, lang); + } + } - if ( subdefault ) - job->select_subtitle_config.default_track = 1; + if( 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; + } + } + } } } @@ -1755,11 +1931,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; @@ -1813,8 +1984,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 @@ -1831,10 +2000,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; @@ -1876,8 +2041,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 @@ -1995,7 +2158,8 @@ 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" - " --dvdnav Use dvdnav (Experimental)\n" + " --no-dvdnav Do not use dvdnav for reading DVDs\n" + " (experimental, enabled by default for testing)\n" "\n" "### Source Options-----------------------------------------------------------\n\n" @@ -2017,7 +2181,7 @@ static void ShowHelp() "### 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" @@ -2034,7 +2198,6 @@ static void ShowHelp() " 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" " -S, --size Set target size\n" " -b, --vb Set video bitrate (default: 1000)\n" " -2, --two-pass Use two-pass mode\n" @@ -2143,12 +2306,13 @@ 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)\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" @@ -2181,19 +2345,37 @@ static void ShowHelp() " --subtitle-burn \"Burn\" the selected subtitle into the video track\n" " If \"number\" is omitted, the first trac is burned.\n" " --subtitle-default Flag the selected subtitle as the default subtitle\n" - " to be displayed upon playback. Settings no default\n" + " to be displayed upon playback. Setting no default\n" " means no subtitle will be automatically displayed\n" " If \"number\" is omitted, the first trac is default.\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" - " --native-language may be used in conjunction with\n" - " a subtitle \"scan\", in which case all tracks\n" - " matching native language will be scanned.\n" - " Otherwise --native-language is mutually exclusive\n" - " 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" @@ -2207,21 +2389,21 @@ static void ShowPresets() { printf("\n< Apple\n"); - 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"); + 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:me=umh:bframes=0:8x8dct=0:trellis=0:subme=6\n"); - 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"); + 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: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 48 -D 0.0 -f mp4 -X 480 -m -x cabac=0:ref=2:mixed-refs:me=umh\n"); + 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:me=umh:bframes=0:subme=6:8x8dct=0:trellis=0\n"); - 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"); + 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:me=umh:b-adapt=2:weightb=0:trellis=0\n"); printf("\n>\n"); printf("\n< Regular\n"); - 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"); + 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: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,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"); + 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 b-pyramid:b-adapt=2:me=umh:subme=9:analyse=all:trellis=0\n"); printf("\n>\n"); @@ -2229,15 +2411,63 @@ static void ShowPresets() printf("\n + Classic: -b 1000 -a 1 -E faac -B 160 -6 dpl2 -R 48 -D 0.0 -f mp4\n"); - 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"); + 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 ref=1: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 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"); + 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:bframes=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 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"); + 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:subme=6:8x8dct=0:trellis=0\n"); printf("\n>\n"); } +static char * hb_strndup( char * str, int len ) +{ + char * res; + int str_len = strlen( str ); + + res = malloc( len > str_len ? str_len + 1 : len + 1 ); + strncpy( res, str, len ); + res[len] = '\0'; + return res; +} + +static char** str_split( char *str, char delem ) +{ + char * pos; + char * end; + char ** ret; + int count, i; + + if ( str == NULL || str[0] == 0 ) + { + ret = malloc( sizeof(char*) ); + *ret = NULL; + return ret; + } + + // Find number of elements in the string + count = 1; + pos = str; + while ( ( pos = strchr( pos, delem ) ) != NULL ) + { + count++; + pos++; + } + + ret = calloc( ( count + 1 ), sizeof(char*) ); + + 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; +} + /**************************************************************************** * ParseOptions: ****************************************************************************/ @@ -2255,6 +2485,12 @@ static int ParseOptions( int argc, char ** argv ) #define KEEP_DISPLAY_ASPECT 265 #define SUB_BURNED 266 #define SUB_DEFAULT 267 + #define NATIVE_DUB 268 + #define SRT_FILE 269 + #define SRT_CODESET 270 + #define SRT_OFFSET 271 + #define SRT_LANG 272 + #define SRT_DEFAULT 273 for( ;; ) { @@ -2264,7 +2500,7 @@ static int ParseOptions( int argc, char ** argv ) { "update", no_argument, NULL, 'u' }, { "verbose", optional_argument, NULL, 'v' }, { "cpu", required_argument, NULL, 'C' }, - { "dvdnav", no_argument, NULL, DVDNAV }, + { "no-dvdnav", no_argument, NULL, DVDNAV }, { "format", required_argument, NULL, 'f' }, { "input", required_argument, NULL, 'i' }, @@ -2285,8 +2521,13 @@ static int ParseOptions( int argc, char ** argv ) { "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' }, @@ -2314,7 +2555,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' }, @@ -2337,7 +2577,7 @@ static int ParseOptions( int argc, char ** argv ) int c; c = getopt_long( argc, argv, - "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", + "hv::uC:f:4i:Io:t:Lc: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 ) { @@ -2377,7 +2617,7 @@ static int ParseOptions( int argc, char ** argv ) ShowPresets(); exit ( 0 ); case DVDNAV: - dvdnav = 1; + dvdnav = 0; break; case 'f': @@ -2453,6 +2693,7 @@ static int ParseOptions( int argc, char ** argv ) if( optarg != NULL ) { atracks = strdup( optarg ); + audio_explicit = 1; } else { @@ -2472,20 +2713,10 @@ static int ParseOptions( int argc, char ** argv ) } break; case 's': - if( optarg != NULL ) - { - subtracks = strdup( optarg ); - } + subtracks = str_split( optarg, ',' ); break; case 'F': - if( optarg != NULL ) - { - subforce = strdup( optarg ); - } - else - { - subforce = "" ; - } + subforce = str_split( optarg, ',' ); break; case SUB_BURNED: if( optarg != NULL ) @@ -2510,6 +2741,31 @@ static int ParseOptions( int argc, char ** argv ) 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; @@ -2696,9 +2952,6 @@ static int ParseOptions( int argc, char ** argv ) abitrates = strdup( optarg ); } break; - case 'Q': - crf = 0; - break; case 'x': x264opts = strdup( optarg ); break; @@ -2787,12 +3040,7 @@ 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" ) || + if( p && ( !strcasecmp( p, ".mp4" ) || !strcasecmp( p, ".m4v" ) ) ) { if ( h264_30 == 1 ) @@ -2801,12 +3049,6 @@ static int CheckOptions( int argc, char ** argv ) mux = HB_MUX_MP4; default_acodec = HB_ACODEC_FAAC; } - else if( p && ( !strcasecmp( p, ".ogm" ) || - !strcasecmp( p, ".ogg" ) ) ) - { - mux = HB_MUX_OGM; - default_acodec = HB_ACODEC_VORBIS; - } else if( p && !strcasecmp(p, ".mkv" ) ) { mux = HB_MUX_MKV; @@ -2819,11 +3061,6 @@ 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" ) ) { @@ -2833,12 +3070,6 @@ static int CheckOptions( int argc, char ** argv ) 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; - } else if( !strcasecmp( format, "mkv" ) ) { mux = HB_MUX_MKV; @@ -2847,7 +3078,7 @@ static int CheckOptions( int argc, char ** argv ) 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; } } @@ -3045,7 +3276,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;