]> granicus.if.org Git - handbrake/commitdiff
Add Subtitle scanning for forced subtitles and normal subtitles from the CLI
authoreddyg <eddyg.hb@myreflection.org>
Tue, 21 Aug 2007 03:24:39 +0000 (03:24 +0000)
committereddyg <eddyg.hb@myreflection.org>
Tue, 21 Aug 2007 03:24:39 +0000 (03:24 +0000)
and the MacOS GUI. See the new subtitle language options in the GUI.

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@844 b64f7644-9d1e-0410-96f1-a4d463321fa5

12 files changed:
libhb/common.h
libhb/decsub.c
libhb/dvd.c
libhb/encavcodec.c
libhb/hb.c
libhb/internal.h
libhb/muxcommon.c
libhb/reader.c
libhb/render.c
libhb/work.c
macosx/Controller.mm
test/test.c

index 22591c60279b77a77fa62415b091522befddfb40..416a93eb6f2ad47512ad9a56398d53d4eb23aee9 100644 (file)
@@ -145,7 +145,7 @@ struct hb_job_s
          vquality:          output quality (0.0..1.0)
                             if < 0.0 or > 1.0, bitrate is used instead
          vbitrate:          output bitrate (kbps)
-         pass:              0, 1 or 2
+         pass:              0, 1 or 2 (or -1 for scan)
          vrate, vrate_base: output framerate is vrate / vrate_base
          h264_level:        boolean for whether or not we're encoding for iPod
          crf:               boolean for whether to use constant rate factor with x264
@@ -378,6 +378,7 @@ struct hb_subtitle_s
     char iso639_2[4];
 
     int hits;     /* How many hits/occurrences of this subtitle */
+    int forced_hits; /* How many forced hits in this subtitle */
 
 #ifdef __LIBHB__
     /* Internal data */
index 443c0865ac3152f4f3db4041e4671049e657cad9..ee269c53b2dfdbb460e77f55c864488c2135f8ca 100644 (file)
@@ -22,6 +22,7 @@ struct hb_work_private_s
     int        y;
     int        width;
     int        height;
+    int        stream_id;
 
     int        offsets[2];
     uint8_t    lum[4];
@@ -53,6 +54,8 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
 
     int size_sub, size_rle;
 
+    pv->stream_id = in->id;
+
     size_sub = ( in->data[0] << 8 ) | in->data[1];
     size_rle = ( in->data[2] << 8 ) | in->data[3];
 
@@ -129,8 +132,9 @@ static void ParseControls( hb_work_object_t * w )
     hb_work_private_t * pv = w->private_data;
     hb_job_t * job = pv->job;
     hb_title_t * title = job->title;
+    hb_subtitle_t * subtitle;
 
-    int i;
+    int i, n;
     int command;
     int date, next;
 
@@ -164,6 +168,23 @@ static void ParseControls( hb_work_object_t * w )
                 case 0x00: // 0x00 - FSTA_DSP - Forced Start Display, no arguments
                     pv->pts_start = pv->pts + date * 900;
                     pv->pts_forced = 1;
+
+                    /*
+                     * If we are doing a subtitle scan then note down
+                     */
+                    if( job->subtitle_scan )
+                    {
+                        for( n=0; n < hb_list_count(title->list_subtitle); n++ ) 
+                        {
+                            subtitle = hb_list_item( title->list_subtitle, n);
+                            if( pv->stream_id == subtitle->id ) {
+                                /*
+                                 * A hit, count it.
+                                 */
+                                subtitle->forced_hits++;
+                            }
+                        }
+                    }
                     break;
 
                 case 0x01: // 0x01 - STA_DSP - Start Display, no arguments
@@ -215,7 +236,7 @@ static void ParseControls( hb_work_object_t * w )
                                pv->chromaU[3-j],
                                pv->chromaV[3-j]); 
                         */
-                    }
+                    } 
                     i += 2;
                     break;
                 }
@@ -412,17 +433,19 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
     /* Get infos about the subtitle */
     ParseControls( w );
 
-    if( job->subtitle_force && pv->pts_forced == 0 )
+    if( job->subtitle_scan || ( job->subtitle_force && pv->pts_forced == 0 ) )
     {
         /*
+         * Don't encode subtitles when doing a scan.
+         *
          * When forcing subtitles, ignore all those that don't
          * have the forced flag set.
          */
         return NULL;
-    } 
+    }
 
     /* Do the actual decoding now */
-    buf_raw = malloc( pv->width * pv->height * 4 );
+    buf_raw = malloc( ( pv->width * pv->height ) * 4 );
 
 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
index 870664f2c13836547d437b90066bf4c800d17b12..c231b378cc8bfbf237416ba62de0678b69474420 100644 (file)
@@ -654,9 +654,23 @@ int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b )
         
         for( ;; )
         {
-            int block, pack_len, next_vobu;
+            int block, pack_len, next_vobu, read_retry;
 
-            if( DVDReadBlocks( d->file, d->next_vobu, 1, b->data ) != 1 )
+            for( read_retry = 0; read_retry < 3; read_retry++ )
+            {
+                if( DVDReadBlocks( d->file, d->next_vobu, 1, b->data ) == 1 )
+                {
+                    /*
+                     * Successful read.
+                     */
+                    break;
+                } else {
+                    hb_log( "dvd: Read Error on blk %d, attempt %d",
+                            d->next_vobu, read_retry );
+                }
+            }
+
+            if( read_retry == 3 )
             {
                 hb_log( "dvd: Unrecoverable Read Error from DVD, potential HD or DVD Failure (blk: %d)", d->next_vobu );
                 return 0;
index 7bccfc7598f419e8c3675ed625dda75f84521e77..85aa6085fdfd4cbf9864bfd143f9537229bc278c 100644 (file)
@@ -87,7 +87,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
         context->flags |= CODEC_FLAG_GRAY;
     }
 
-    if( job->pass )
+    if( job->pass != 0 && job->pass != -1 )
     {
         char filename[1024]; memset( filename, 0, 1024 );
         hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
index 861da0702b91ad879e9b5809feeb1784ea8c870b..4ffb62c8572731855d0cfc038e0d707abe243abe 100644 (file)
@@ -23,6 +23,7 @@ struct hb_handle_s
     /* The thread which processes the jobs. Others threads are launched
        from this one (see work.c) */
     hb_list_t    * jobs;
+    hb_job_t     * current_job;
     int            job_count;
     int            job_count_permanent;
     volatile int   work_die;
@@ -186,6 +187,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check )
 
     h->list_title = hb_list_init();
     h->jobs       = hb_list_init();
+    h->current_job = NULL;
 
     h->state_lock  = hb_lock_init();
     h->state.state = HB_STATE_IDLE;
@@ -509,6 +511,11 @@ hb_job_t * hb_job( hb_handle_t * h, int i )
     return hb_list_item( h->jobs, i );
 }
 
+hb_job_t * hb_current_job( hb_handle_t * h )
+{
+    return( h->current_job );
+}
+
 /**
  * Adds a job to the job list.
  * @param h Handle to hb_handle_t.
@@ -542,7 +549,7 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
     title_copy->list_audio = hb_list_init();
 
     /* Do nothing about audio during first pass */
-    if( job->pass != 1 )
+    if( job->pass == 0 || job->pass == 2 )
     {
         for( i = 0; i < 8; i++ )
         {
@@ -562,19 +569,21 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
     title_copy->list_subtitle = hb_list_init();
 
     /*
-     * The following code is confusing, there are three ways in which we select subtitles
-     * and it depends on whether this is single or two pass mode.
+     * The following code is confusing, there are three ways in which
+     * we select subtitles and it depends on whether this is single or
+     * two pass mode.
      *
-     * subtitle_scan may be enabled, in which case the first pass scans all subtitles
-     * of that language. The second pass does not select any because they are set at the
-     * end of the first pass.
+     * subtitle_scan may be enabled, in which case the first pass
+     * scans all subtitles of that language. The second pass does not
+     * select any because they are set at the end of the first pass.
      *
-     * native_language may have a preferred language, in which case we may be switching
-     * the language we want for the subtitles in the first pass of a single pass, or the
-     * second pass of a two pass.
+     * native_language may have a preferred language, in which case we
+     * may be switching the language we want for the subtitles in the
+     * first pass of a single pass, or the second pass of a two pass.
      *
-     * We may have manually selected a subtitle, in which case that is selected in the
-     * first pass of a single pass, or the second of a two pass.
+     * We may have manually selected a subtitle, in which case that is
+     * selected in the first pass of a single pass, or the second of a
+     * two pass.
      */
     memset( audio_lang, 0, sizeof( audio_lang ) );
 
@@ -666,7 +675,7 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
         {
             /*
              * Don't add subtitles here, we'll add them via select_subtitle
-             * at the end of pass 1
+             * at the end of the subtitle_scan.
              */
         } else {
             /*
@@ -786,7 +795,7 @@ void hb_start( hb_handle_t * h )
 
     h->work_die    = 0;
     h->work_thread = hb_work_init( h->jobs, h->cpu_count,
-                                   &h->work_die, &h->work_error );
+                                   &h->work_die, &h->work_error, &h->current_job );
 }
 
 /**
index b4870a128f03c403bcf7611264fcef3108027cbf..cf0f7fade068fd91d97b74eb0a530016894c06fb 100644 (file)
@@ -86,7 +86,7 @@ hb_thread_t * hb_update_init( int * build, char * version );
 hb_thread_t * hb_scan_init( hb_handle_t *, const char * path,
                             int title_index, hb_list_t * list_title );
 hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count,
-                            volatile int * die, int * error );
+                            volatile int * die, int * error, hb_job_t ** job );
 hb_thread_t  * hb_reader_init( hb_job_t * );
 hb_thread_t  * hb_muxer_init( hb_job_t * );
 
index 009b81bd645bb179973c9fbc7f0c3d87d46e3a7e..d6a8270da637a50ec55625399ff92fbc39b5ab50 100644 (file)
@@ -65,7 +65,7 @@ static void MuxerFunc( void * _mux )
     hb_mux_object_t * m = NULL;
 
     /* Get a real muxer */
-    if( job->pass != 1 )
+    if( job->pass == 0 || job->pass == 2)
     {
         switch( job->mux )
         {
@@ -114,7 +114,7 @@ static void MuxerFunc( void * _mux )
     }
 
     /* Create file, write headers */
-    if( job->pass != 1 )
+    if( job->pass == 0 || job->pass == 2 )
     {
         m->init( m );
     }
@@ -148,7 +148,7 @@ static void MuxerFunc( void * _mux )
 //             thread_sleep_interval = MAX(1, (thread_sleep_interval - 1));
 
         buf = hb_fifo_get( track->fifo );
-        if( job->pass != 1 )
+        if( job->pass == 0 || job->pass == 2 )
         {
             m->mux( m, track->mux_data, buf );
             track->frames += 1;
@@ -158,7 +158,7 @@ static void MuxerFunc( void * _mux )
         hb_buffer_close( &buf );
     }
 
-    if( job->pass != 1 )
+    if( job->pass == 0 || job->pass == 2 )
     {
         struct stat sb;
         uint64_t bytes_total, frames_total;
index 335dfb80d48bad61ea7bb26143c66ed7df9c4564..8980c1cc6c8bbab2ba494337fa6685fd8b987f74 100644 (file)
@@ -172,12 +172,23 @@ static hb_fifo_t * GetFifoForId( hb_job_t * job, int id )
 
     if( id == 0xE0 )
     {
-        return job->fifo_mpeg2;
+        if( !job->subtitle_scan )
+        {
+            return job->fifo_mpeg2;
+        } else {
+            /*
+             * Ditch the mpeg2 video when doing a subtitle scan.
+             */
+            return NULL;
+        }
     }
 
     if (job->subtitle_scan) {
         /*
-         * Count the occurances of the subtitles, don't actually return any to encode.
+         * Count the occurances of the subtitles, don't actually
+         * return any to encode unless we are looking fro forced
+         * subtitles in which case we need to look in the sub picture
+         * to see if it has the forced flag enabled.
          */
         for (i=0; i < hb_list_count(title->list_subtitle); i++) {
             subtitle =  hb_list_item( title->list_subtitle, i);
@@ -186,6 +197,11 @@ static hb_fifo_t * GetFifoForId( hb_job_t * job, int id )
                  * A hit, count it.
                  */
                 subtitle->hits++;
+                if( job->subtitle_force )
+                {
+                    return subtitle->fifo_in;
+                }
+                break;
             }
         }
     } else {
index a8abd0e75a12ea5371d0d64e93b012647a6c319c..e8fe0aef2043da8437e12e6d1ca383e76d582211 100644 (file)
@@ -112,7 +112,7 @@ static void ApplySub( hb_job_t * job, hb_buffer_t * buf,
                      * Merge the luminance and alpha with the picture
                      */
                     out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) +
-                               (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4;
+                               (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4;   
                     /*
                      * Set the chroma (colour) based on whether there is
                      * any alpha at all. Don't try to blend with the picture.
index 77e0c921c97e30c89de47184039c9cc080c14881..0302a3d144ab80e455cc2cc3bbf1a0aa386aeca4 100644 (file)
@@ -11,6 +11,7 @@
 typedef struct
 {
     hb_list_t * jobs;
+    hb_job_t  ** current_job;
     int         cpu_count;
     int       * error;
     volatile int * die;
@@ -29,11 +30,12 @@ static void work_loop( void * );
  * @param error Handle to error indicator.
  */
 hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count,
-                            volatile int * die, int * error )
+                            volatile int * die, int * error, hb_job_t ** job )
 {
     hb_work_t * work = calloc( sizeof( hb_work_t ), 1 );
 
     work->jobs      = jobs;
+    work->current_job = job;
     work->cpu_count = cpu_count;
     work->die       = die;
     work->error     = error;
@@ -56,7 +58,9 @@ static void work_func( void * _work )
     {
         hb_list_rem( work->jobs, job );
         job->die = work->die;
+        *(work->current_job) = job;
         do_job( job, work->cpu_count );
+        *(work->current_job) = NULL;
     }
 
     *(work->error) = HB_ERROR_NONE;
@@ -96,6 +100,7 @@ static void do_job( hb_job_t * job, int cpu_count )
     
     /* FIXME: This feels really hackish, anything better? */
     hb_work_object_t * audio_w = NULL;
+    hb_work_object_t * sub_w = NULL;
 
     hb_audio_t   * audio;
     hb_subtitle_t * subtitle;
@@ -104,6 +109,7 @@ static void do_job( hb_job_t * job, int cpu_count )
     unsigned int subtitle_highest_id = 0;
     unsigned int subtitle_lowest = -1;
     unsigned int subtitle_lowest_id = 0;
+    unsigned int subtitle_forced_id = 0;
     unsigned int subtitle_hit = 0;
 
     title = job->title;
@@ -217,7 +223,10 @@ static void do_job( hb_job_t * job, int cpu_count )
          * add the subtitle that we found on the first pass for use in this
          * pass.
          */
-        hb_list_add( title->list_subtitle, *( job->select_subtitle ) );
+        if (*(job->select_subtitle))
+        {
+            hb_list_add( title->list_subtitle, *( job->select_subtitle ) );
+        }
     }
 
     for( i=0; i < hb_list_count(title->list_subtitle); i++ ) 
@@ -231,13 +240,40 @@ static void do_job( hb_job_t * job, int cpu_count )
             subtitle->fifo_in  = hb_fifo_init( 8 );
             subtitle->fifo_raw = hb_fifo_init( 8 );
             
-            if (!job->subtitle_scan) {
+            /*
+             * Disable forced subtitles if we didn't find any in the scan
+             * so that we display normal subtitles instead.
+             *
+             * select_subtitle implies that we did a scan.
+             */
+            if( !job->subtitle_scan && job->subtitle_force && 
+                job->select_subtitle ) 
+            {
+                if( subtitle->forced_hits == 0 )
+                {
+                    job->subtitle_force = 0;
+                }
+            }
+
+            if (!job->subtitle_scan || job->subtitle_force) {
                 /*
-                 * Don't add threads for subtitles when we are scanning
+                 * Don't add threads for subtitles when we are scanning, unless
+                 * looking for forced subtitles.
                  */
-                hb_list_add( job->list_work, ( w = getWork( WORK_DECSUB ) ) );
-                w->fifo_in  = subtitle->fifo_in;
-                w->fifo_out = subtitle->fifo_raw;
+                if( sub_w != NULL )
+                { 
+                    /*
+                     * Need to copy the prior subtitle structure so that we
+                     * don't overwrite the fifos.
+                     */
+                    sub_w = calloc( sizeof( hb_work_object_t ), 1 );
+                    sub_w = memcpy( sub_w, w, sizeof( hb_work_object_t ));
+                } else {
+                    w = sub_w = getWork( WORK_DECSUB );
+                }
+                hb_list_add( job->list_work, sub_w );
+                sub_w->fifo_in  = subtitle->fifo_in;
+                sub_w->fifo_out = subtitle->fifo_raw;
             }
         }
     }
@@ -563,8 +599,9 @@ static void do_job( hb_job_t * job, int cpu_count )
         for( i=0; i < hb_list_count( title->list_subtitle ); i++ ) 
         {
             subtitle =  hb_list_item( title->list_subtitle, i );
-            hb_log( "Subtitle stream 0x%x '%s': %d hits",
-                    subtitle->id, subtitle->lang, subtitle->hits );
+            hb_log( "Subtitle stream 0x%x '%s': %d hits (%d forced)",
+                    subtitle->id, subtitle->lang, subtitle->hits,
+                    subtitle->forced_hits );
             if( subtitle->hits > subtitle_highest ) 
             {
                 subtitle_highest = subtitle->hits;
@@ -576,6 +613,11 @@ static void do_job( hb_job_t * job, int cpu_count )
                 subtitle_lowest = subtitle->hits;
                 subtitle_lowest_id = subtitle->id;
             }
+
+            if ( subtitle->forced_hits > 0 )
+            {
+                subtitle_forced_id = subtitle->id;
+            }
         }
         
         if( job->native_language ) {
@@ -587,11 +629,21 @@ static void do_job( hb_job_t * job, int cpu_count )
             subtitle_hit = subtitle_highest_id;
             hb_log( "Found a native-language subtitle id 0x%x", subtitle_hit);
         } else {
-            if( subtitle_lowest < subtitle_highest ) 
+            if( subtitle_forced_id )
+            {
+                /*
+                 * If there are any subtitle streams with forced subtitles
+                 * then select it in preference to the lowest.
+                 */
+                subtitle_hit = subtitle_forced_id;
+                hb_log("Found a subtitle candidate id 0x%x (contains forced subs)",
+                       subtitle_hit);
+            } else if( subtitle_lowest < subtitle_highest ) 
             {
                 /*
-                 * OK we have more than one, and the lowest is lower, but how much
-                 * lower to qualify for turning it on by default?
+                 * OK we have more than one, and the lowest is lower,
+                 * but how much lower to qualify for turning it on by
+                 * default?
                  *
                  * Let's say 10% as a default.
                  */
@@ -614,7 +666,7 @@ static void do_job( hb_job_t * job, int cpu_count )
             for( i=0; i < hb_list_count( title->list_subtitle ); i++ ) 
             {
                 subtitle =  hb_list_item( title->list_subtitle, i );
-                if( subtitle->id = subtitle_hit ) 
+                if( subtitle->id == subtitle_hit ) 
                 {
                     hb_list_rem( title->list_subtitle, subtitle );
                     *( job->select_subtitle ) = subtitle;
@@ -622,7 +674,10 @@ static void do_job( hb_job_t * job, int cpu_count )
             }
         } else {
             /*
-             * Must be the second pass - we don't need this anymore.
+             * Must be the end of pass 0 or 2 - we don't need this anymore.
+             *
+             * Have to put the subtitle list back together in the title though
+             * or the GUI will have a hissy fit.
              */
             free( job->select_subtitle );
             job->select_subtitle = NULL;
index b3d7f1dbc40422cbba426b11932314cc13624014..6209966470e9176e44cc1a72f2f620803093d27d 100644 (file)
@@ -1431,7 +1431,7 @@ list = hb_get_titles( fHandle );
 
 
     /* Subtitle settings */
-    job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
+    job->subtitle = [fSubPopUp indexOfSelectedItem] - 3;
 
     /* Audio tracks and mixdowns */
     /* check for the condition where track 2 has an audio selected, but track 1 does not */
@@ -1545,20 +1545,77 @@ list = hb_get_titles( fHandle );
                
                /* Destination file */
                job->file = [[fDstFile2Field stringValue] UTF8String];
-               
+
+                if( job->subtitle == -1 )
+                {
+                    job->subtitle_force = 1;
+                } else {
+                    job->subtitle_force = 0;
+                }
+
+                /*
+                 * subtitle of -1 and -2 is a scan
+                 */
+                if( job->subtitle == -1 ||
+                    job->subtitle == -2 )
+                {
+                    char *x264opts_tmp;
+
+                    /*
+                     * When subtitle scan is enabled do a fast pre-scan job
+                     * which will determine which subtitles to enable, if any.
+                     */
+                    job->pass = -1;
+                    x264opts_tmp = job->x264opts;
+                    job->subtitle = -1;
+
+                    job->x264opts = NULL;
+                    
+                    job->subtitle_scan = 1;  
+
+                    job->select_subtitle = (hb_subtitle_t**)malloc(sizeof(hb_subtitle_t*));
+                    *(job->select_subtitle) = NULL;
+                    
+                    /*
+                     * Add the pre-scan job
+                     */
+                    hb_add( fHandle, job );
+
+                    job->x264opts = x264opts_tmp;
+                } else {
+                    job->select_subtitle = NULL;
+                }
+
+                /* No subtitle were selected, so reset the subtitle to -1 (which before
+                 * this point meant we were scanning
+                 */
+                if( job->subtitle == -3 )
+                {
+                    job->subtitle = -1;
+                }
+
                if( [fVidTwoPassCheck state] == NSOnState )
                {
+                        hb_subtitle_t **subtitle_tmp = job->select_subtitle;
+
+                        job->select_subtitle = NULL;
+
+                        job->subtitle_scan = 0;
+
                        job->pass = 1;
                        hb_add( fHandle, job );
                        job->pass = 2;
                        
                        job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
                        strcpy(job->x264opts, [[fDisplayX264Options stringValue] UTF8String]);
-                       
+
+                        job->select_subtitle = subtitle_tmp;
+
                        hb_add( fHandle, job );
                }
                else
                {
+                        job->subtitle_scan = 0;
                        job->pass = 0;
                        hb_add( fHandle, job );
                }
@@ -1797,6 +1854,8 @@ list = hb_get_titles( fHandle );
     hb_subtitle_t * subtitle;
     [fSubPopUp removeAllItems];
     [fSubPopUp addItemWithTitle: @"None"];
+    [fSubPopUp addItemWithTitle: @"Autoselect"];
+    [fSubPopUp addItemWithTitle: @"Autoselect (forced only)"];
     for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
     {
         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
index 1aa808f8706ba7b88200dcbbd6d2c65a81f0497b..85d506f6e191e053c4f78bc90acc46ee44533e9f 100644 (file)
@@ -598,12 +598,40 @@ static int HandleEvents( hb_handle_t * h )
                 job->maxWidth = maxWidth;
             if (maxHeight)
                 job->maxHeight = maxHeight;
-
+       
             if( subtitle_force )
             {
                 job->subtitle_force = subtitle_force;
-            } 
-               
+            }
+
+            if( subtitle_scan )
+            {
+                char *x264opts_tmp;
+
+                /*
+                 * When subtitle scan is enabled do a fast pre-scan job
+                 * which will determine which subtitles to enable, if any.
+                 */
+                job->pass = -1;
+                
+                x264opts_tmp = job->x264opts;
+
+                job->x264opts = NULL;
+
+                job->subtitle_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
+                 */
+                hb_add( h, job );
+
+                job->x264opts = x264opts_tmp;
+            }
+
             if( twoPass )
             {
                 /*
@@ -611,15 +639,13 @@ 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->subtitle_scan = subtitle_scan;
-                if( 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;
-                } 
+
+                job->subtitle_scan = 0;
 
                 /*
                  * If turbo options have been selected then append them
@@ -652,6 +678,9 @@ static int HandleEvents( hb_handle_t * h )
                     job->x264opts = x264opts;
                 }     
                 hb_add( h, job );
+
+                job->select_subtitle = subtitle_tmp;
+
                 job->pass = 2;
                 /*
                  * On the second pass we turn off subtitle scan so that we
@@ -670,11 +699,9 @@ static int HandleEvents( hb_handle_t * h )
                 /*
                  * Turn on subtitle scan if requested, note that this option
                  * precludes encoding of any actual subtitles.
-                 */
-                if ( subtitle_scan ) 
-                {
-                    fprintf( stderr, "Warning: Subtitle Scan only works in two-pass, disabling\n");
-                }
+                 */ 
+
+                job->subtitle_scan = 0;
                 job->pass = 0;
                 hb_add( h, job );
             }
@@ -791,8 +818,10 @@ static void ShowHelp()
     "                            the one that's only used 10 percent of the time\n"
     "                            or less. This should locate subtitles for short\n"
     "                            foreign language segments. Only works with 2-pass.\n"
-    "    -F, --subtitle-force    Only display subtitles from the selected stream if\n"
-    "                            the subtitles have the forced flag set.\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"
     "          <string>          match the Audio language. Provide the language's\n"
     "                            iso639-2 code (fre, eng, spa, dut, et cetera)\n"