#include <unistd.h>
#include <inttypes.h>
-#ifdef PTW32_STATIC_LIB
+#if defined( __MINGW32__ )
+#include <conio.h>
+#endif
+
+#if defined( PTW32_STATIC_LIB )
#include <pthread.h>
#endif
#include "hb.h"
#include "parsecsv.h"
-#ifdef __APPLE_CC__
+#if defined( __APPLE_CC__ )
#import <CoreServices/CoreServices.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOMedia.h>
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;
static char * anames = NULL;
static int default_acodec = HB_ACODEC_FAAC;
static int default_abitrate = 160;
+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 subtitle_scan = 0;
static int width = 0;
static int height = 0;
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 */
return 1;
}
-#ifdef PTW32_STATIC_LIB
+#if defined( PTW32_STATIC_LIB )
pthread_win32_process_attach_np();
pthread_win32_thread_attach_np();
#endif
/* 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;
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
static void PrintTitleInfo( hb_title_t * title )
{
hb_chapter_t * chapter;
- hb_audio_config_t * audio;
hb_subtitle_t * subtitle;
int i;
}
/* 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 )
+ {
/* Create a new audio track with default settings */
audio = calloc(1, sizeof(*audio));
hb_audio_config_init(audio);
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
subtitle = hb_list_item(title->list_subtitle, track);
if( subtitle == NULL )
{
- fprintf( stderr, "Could not find subtitle track %d, skipped\n", track );
+ fprintf( stderr, "Warning: Could not find subtitle track %d, skipped\n", track+1 );
continue;
}
sub_config = subtitle->config;
subtitle->format == PICTURESUB)
{
// Skip any non-burned vobsubs when output is mp4
+ 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 )
// 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;
}
-
sub_config.force = force;
sub_config.default_track = def;
hb_subtitle_add( job, &sub_config, track );
}
}
- 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";
- if ( subburn == NULL && mux != HB_MUX_MP4 )
- job->select_subtitle_config.force = 1;
+ 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.force = 0;
+ sub_config.default_track = 0;
+ strncpy( sub_config.src_filename, srtfile[i], 128);
+ strncpy( sub_config.src_codeset, codeset, 40);
+ sub_config.offset = offset;
- if ( subdefault )
- job->select_subtitle_config.default_track = 1;
+ hb_srt_add( job, &sub_config, lang);
+ }
+ }
+
+ 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;
+ }
+ }
+ }
}
}
" <number> to be displayed upon playback. Settings 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"
- " <string> 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"
+ " <string> 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 <string> SubRip SRT filename(s), separated by commas.\n"
+ " --srt-codeset Character codeset(s) that the SRT file(s) are\n"
+ " <string> 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"
+ " <string> separted by commas. If not specified zero is assumed.\n"
+ " Offsets may be negative.\n"
+ " --srt-lang <string> 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"
"\n"
#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
for( ;; )
{
{ "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 },
{ "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' },
if( optarg != NULL )
{
atracks = strdup( optarg );
+ audio_explicit = 1;
}
else
{
subtracks = str_split( optarg, "," );
break;
case 'F':
- subtracks = str_split( optarg, "," );
+ subforce = str_split( optarg, "," );
break;
case SUB_BURNED:
if( optarg != NULL )
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 '2':
twoPass = 1;
break;
* 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;