OSDN Git Service

Bump libmkv to 0.6.4.1
[handbrake-jp/handbrake-jp-git.git] / libhb / scan.c
index de4d565..68188a2 100644 (file)
@@ -8,16 +8,23 @@
 #include "a52dec/a52.h"
 #include "dca.h"
 
+#define HB_MAX_PREVIEWS 30 // 30 previews = every 5 minutes of a 2.5 hour video
+
 typedef struct
 {
-    hb_handle_t * h;
+    hb_handle_t  * h;
+    volatile int * die;
 
-    char        * path;
-    int           title_index;
-    hb_list_t   * list_title;
+    char         * path;
+    int            title_index;
+    hb_list_t    * list_title;
 
-    hb_dvd_t    * dvd;
-       hb_stream_t * stream;
+    hb_dvd_t     * dvd;
+    hb_stream_t  * stream;
+    hb_batch_t   * batch;
+       
+    int            preview_count;
+    int            store_previews;
 
 } hb_scan_t;
 
@@ -38,16 +45,22 @@ static const char *aspect_to_string( double aspect )
     return arstr;
 }
 
-hb_thread_t * hb_scan_init( hb_handle_t * handle, const char * path,
-                            int title_index, hb_list_t * list_title )
+hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die,
+                            const char * path, int title_index, 
+                            hb_list_t * list_title, int preview_count, 
+                            int store_previews )
 {
     hb_scan_t * data = calloc( sizeof( hb_scan_t ), 1 );
 
     data->h            = handle;
+    data->die          = die;
     data->path         = strdup( path );
     data->title_index  = title_index;
     data->list_title   = list_title;
-
+    
+    data->preview_count  = preview_count;
+    data->store_previews = store_previews;
+    
     return hb_thread_init( "scan", ScanFunc, data, HB_NORMAL_PRIORITY );
 }
 
@@ -56,6 +69,7 @@ static void ScanFunc( void * _data )
     hb_scan_t  * data = (hb_scan_t *) _data;
     hb_title_t * title;
     int          i;
+    int          feature = 0;
 
        data->dvd = NULL;
        data->stream = NULL;
@@ -80,6 +94,24 @@ static void ScanFunc( void * _data )
                 hb_list_add( data->list_title,
                              hb_dvd_title_scan( data->dvd, i + 1 ) );
             }
+            feature = hb_dvd_main_feature( data->dvd, data->list_title );
+        }
+    }
+    else if ( ( data->batch = hb_batch_init( data->path ) ) )
+    {
+        int j = 1;
+
+        /* Scan all titles */
+        for( i = 0; i < hb_batch_title_count( data->batch ); i++ )
+        {
+            hb_title_t * title;
+
+            title = hb_batch_title_scan( data->batch, i );
+            if ( title != NULL )
+            {
+                title->index = j++;
+                hb_list_add( data->list_title, title );
+            }
         }
     }
     else if ( (data->stream = hb_stream_open( data->path, 0 ) ) != NULL )
@@ -97,35 +129,12 @@ static void ScanFunc( void * _data )
         int j;
         hb_state_t state;
         hb_audio_t * audio;
-        hb_title_t * title_tmp = NULL;
 
-        title = hb_list_item( data->list_title, i );
-
-        /* I've seen a DVD with strictly identical titles. Check this
-           here and ignore it if redundant */
-        for( j = 0; j < i; j++ )
-        {
-            title_tmp = hb_list_item( data->list_title, j );
-            if( title->vts         == title_tmp->vts &&
-                title->block_start == title_tmp->block_start &&
-                title->block_end   == title_tmp->block_end &&
-                title->block_count == title_tmp->block_count )
-            {
-                break;
-            }
-            else
-            {
-                title_tmp = NULL;
-            }
-        }
-        if( title_tmp )
+        if ( *data->die )
         {
-            hb_log( "scan: title %d is duplicate with title %d",
-                    title->index, title_tmp->index );
-            hb_list_rem( data->list_title, title );
-            free( title );      /* This _will_ leak! */
-            continue;
+                       goto finish;
         }
+        title = hb_list_item( data->list_title, i );
 
 #define p state.param.scanning
         /* Update the UI */
@@ -156,17 +165,30 @@ static void ScanFunc( void * _data )
                 free( audio );
                 continue;
             }
+            if ( audio->priv.scan_cache )
+            {
+                hb_fifo_flush( audio->priv.scan_cache );
+                hb_fifo_close( &audio->priv.scan_cache );
+            }
             j++;
         }
 
-        /* If we don't have any audio streams left, remove the title */
-        if( !hb_list_count( title->list_audio ) )
+        if ( data->dvd )
         {
-            hb_list_rem( data->list_title, title );
-            free( title );
-            continue;
+            // The subtitle width and height needs to be set to the 
+            // title widht and height for DVDs.  title width and
+            // height don't get set until we decode previews, so
+            // we can't set subtitle width/height till we get here.
+            for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
+            {
+                hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, j );
+                if ( subtitle->source == VOBSUB )
+                {
+                    subtitle->width = title->width;
+                    subtitle->height = title->height;
+                }
+            }
         }
-
         i++;
     }
 
@@ -180,6 +202,7 @@ static void ScanFunc( void * _data )
         title->job = job;
 
         job->title = title;
+        job->feature = feature;
 
         /* Set defaults settings */
         job->chapter_start = 1;
@@ -191,15 +214,15 @@ static void ScanFunc( void * _data )
         /* Preserve a source's pixel aspect, if it's available. */
         if( title->pixel_aspect_width && title->pixel_aspect_height )
         {
-            job->pixel_aspect_width  = title->pixel_aspect_width;
-            job->pixel_aspect_height = title->pixel_aspect_height;
+            job->anamorphic.par_width  = title->pixel_aspect_width;
+            job->anamorphic.par_height = title->pixel_aspect_height;
         }
 
         if( title->aspect != 0 && title->aspect != 1. &&
-            !job->pixel_aspect_width && !job->pixel_aspect_height)
+            !job->anamorphic.par_width && !job->anamorphic.par_height)
         {
-            hb_reduce( &job->pixel_aspect_width, &job->pixel_aspect_height,
-                       (int)(title->aspect * title->height), title->width );
+            hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height,
+                       (int)(title->aspect * title->height + 0.5), title->width );
         }
 
         job->width = title->width - job->crop[2] - job->crop[3];
@@ -223,12 +246,13 @@ static void ScanFunc( void * _data )
         job->vrate_base = title->rate_base;
 
         job->list_audio = hb_list_init();
-
-        job->subtitle = -1;
+        job->list_subtitle = hb_list_init();
 
         job->mux = HB_MUX_MP4;
     }
 
+finish:
+
     if( data->dvd )
     {
         hb_dvd_close( &data->dvd );
@@ -237,6 +261,10 @@ static void ScanFunc( void * _data )
        {
                hb_stream_close(&data->stream);
        }
+    if( data->batch )
+    {
+        hb_batch_close( &data->batch );
+    }
     free( data->path );
     free( data );
     _data = NULL;
@@ -315,10 +343,10 @@ static int column_all_dark( hb_title_t *title, uint8_t* luma, int top, int botto
 
 typedef struct {
     int n;
-    int t[10];
-    int b[10];
-    int l[10];
-    int r[10];
+    int t[HB_MAX_PREVIEWS];
+    int b[HB_MAX_PREVIEWS];
+    int l[HB_MAX_PREVIEWS];
+    int r[HB_MAX_PREVIEWS];
 } crop_record_t;
 
 static void record_crop( crop_record_t *crops, int t, int b, int l, int r )
@@ -396,7 +424,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
     hb_list_t     * list_es;
     int progressive_count = 0;
     int interlaced_preview_count = 0;
-    info_list_t * info_list = calloc( 10+1, sizeof(*info_list) );
+    info_list_t * info_list = calloc( data->preview_count+1, sizeof(*info_list) );
     crop_record_t *crops = calloc( 1, sizeof(*crops) );
 
     buf_ps   = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
@@ -405,17 +433,29 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
     hb_log( "scan: decoding previews for title %d", title->index );
 
     if (data->dvd)
-      hb_dvd_start( data->dvd, title->index, 1 );
+    {
+        hb_dvd_start( data->dvd, title, 1 );
+        title->angle_count = hb_dvd_angle_count( data->dvd );
+        hb_log( "scan: title angle(s) %d", title->angle_count );
+    }
+    else if (data->batch)
+    {
+        data->stream = hb_stream_open( title->path, title );
+    }
 
-    for( i = 0; i < 10; i++ )
+    for( i = 0; i < data->preview_count; i++ )
     {
         int j;
         FILE * file_preview;
         char   filename[1024];
 
+        if ( *data->die )
+        {
+            return 0;
+        }
         if (data->dvd)
         {
-          if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / 11.0 ) )
+          if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / ( data->preview_count + 1.0 ) ) )
           {
               continue;
           }
@@ -425,19 +465,35 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
           /* we start reading streams at zero rather than 1/11 because
            * short streams may have only one sequence header in the entire
            * file and we need it to decode any previews. */
-          if (!hb_stream_seek(data->stream, (float) i / 11.0 ) )
+          if (!hb_stream_seek(data->stream, (float) i / ( data->preview_count + 1.0 ) ) )
           {
               continue;
           }
         }
 
-        hb_log( "scan: preview %d", i + 1 );
+        hb_deep_log( 2, "scan: preview %d", i + 1 );
 
         int vcodec = title->video_codec? title->video_codec : WORK_DECMPEG2;
         hb_work_object_t *vid_decoder = hb_get_work( vcodec );
         vid_decoder->codec_param = title->video_codec_param;
+        vid_decoder->title = title;
         vid_decoder->init( vid_decoder, NULL );
         hb_buffer_t * vid_buf = NULL;
+        int vidskip = 0;
+
+        if ( title->flags & HBTF_NO_IDR )
+        {
+            // title doesn't have IDR frames so we decode but drop one second's
+            // worth of frames to allow the decoder to converge.
+            if ( ! title->rate_base )
+            {
+                vidskip = 30;
+            }
+            else
+            {
+                vidskip = (double)title->rate / (double)title->rate_base + 0.5;
+            }
+        }
 
         for( j = 0; j < 10240 ; j++ )
         {
@@ -445,6 +501,10 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
             {
               if( !hb_dvd_read( data->dvd, buf_ps ) )
               {
+                  if ( vid_buf )
+                  {
+                    break;
+                  }
                   hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                   goto skip_preview;
               }
@@ -453,18 +513,15 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
             {
               if ( !hb_stream_read(data->stream,buf_ps) )
               {
+                  if ( vid_buf )
+                  {
+                    break;
+                  }
                   hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                   goto skip_preview;
               }
             }
-            if ( title->demuxer == HB_NULL_DEMUXER )
-            {
-                hb_demux_null( buf_ps, list_es, 0 );
-            }
-            else
-            {
-                hb_demux_ps( buf_ps, list_es, 0 );
-            }
+            (hb_demux[title->demuxer])(buf_ps, list_es, 0 );
 
             while( ( buf_es = hb_list_item( list_es, 0 ) ) )
             {
@@ -472,10 +529,18 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
                 if( buf_es->id == title->video_id && vid_buf == NULL )
                 {
                     vid_decoder->work( vid_decoder, &buf_es, &vid_buf );
+                    if ( vid_buf && vidskip && --vidskip > 0 )
+                    {
+                        // we're dropping frames to get the video decoder in sync
+                        // when the video stream doesn't contain IDR frames
+                        hb_buffer_close( &vid_buf );
+                        vid_buf = NULL;
+                    }
                 }
-                else if( ! AllAudioOK( title ) )
+                else if( ! AllAudioOK( title ) ) 
                 {
                     LookForAudio( title, buf_es );
+                    buf_es = NULL;
                 }
                 if ( buf_es )
                     hb_buffer_close( &buf_es );
@@ -497,9 +562,9 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
         if( !vid_decoder->info( vid_decoder, &vid_info ) )
         {
             /*
-               * Could not fill vid_info, don't continue and try to use vid_info
-               * in this case.
-               */
+             * Could not fill vid_info, don't continue and try to use vid_info
+             * in this case.
+             */
             vid_decoder->close( vid_decoder );
             free( vid_decoder );
             continue;
@@ -540,7 +605,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
                 */
                 if( progressive_count == 6 )
                 {
-                    hb_log("Title's mostly NTSC Film, setting fps to 23.976");
+                    hb_deep_log( 2, "Title's mostly NTSC Film, setting fps to 23.976");
                 }
                 title->rate_base = 1126125;
             }
@@ -563,23 +628,26 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
         /* Check preview for interlacing artifacts */
         if( hb_detect_comb( vid_buf, title->width, title->height, 10, 30, 9, 10, 30, 9 ) )
         {
-            hb_log("Interlacing detected in preview frame %i", i+1);
+            hb_deep_log( 2, "Interlacing detected in preview frame %i", i+1);
             interlaced_preview_count++;
         }
-
-        hb_get_tempory_filename( data->h, filename, "%x%d",
-                                 (intptr_t)title, i );
-
-        file_preview = fopen( filename, "w" );
-        if( file_preview )
-        {
-            fwrite( vid_buf->data, title->width * title->height * 3 / 2,
-                    1, file_preview );
-            fclose( file_preview );
-        }
-        else
+        
+        if( data->store_previews )
         {
-            hb_log( "scan: fopen failed (%s)", filename );
+            hb_get_tempory_filename( data->h, filename, "%d_%d_%d",
+                                     hb_get_instance_id(data->h), title->index, i );
+
+            file_preview = fopen( filename, "wb" );
+            if( file_preview )
+            {
+                fwrite( vid_buf->data, title->width * title->height * 3 / 2,
+                        1, file_preview );
+                fclose( file_preview );
+            }
+            else
+            {
+                hb_log( "scan: fopen failed (%s)", filename );
+            }
         }
 
         /* Detect black borders */
@@ -655,10 +723,24 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
         ++npreviews;
 
 skip_preview:
+        /* Make sure we found audio rates and bitrates */
+        for( j = 0; j < hb_list_count( title->list_audio ); j++ )
+        {
+            hb_audio_t * audio = hb_list_item( title->list_audio, j );
+            if ( audio->priv.scan_cache )
+            {
+                hb_fifo_flush( audio->priv.scan_cache );
+            }
+        }
         if ( vid_buf )
             hb_buffer_close( &vid_buf );
     }
 
+    if ( data->batch && data->stream )
+    {
+        hb_stream_close( &data->stream );
+    }
+
     if ( npreviews )
     {
         // use the most common frame info for our final title dimensions
@@ -685,14 +767,14 @@ skip_preview:
             // aspect ratio from the DVD metadata. So, if the aspect computed
             // from the PAR is different from the container's aspect we use
             // the container's aspect & recompute the PAR from it.
-            if( title->container_aspect && title->aspect != title->container_aspect )
+            if( title->container_aspect && (int)(title->aspect * 9) != (int)(title->container_aspect * 9) )
             {
                 hb_log("scan: content PAR gives wrong aspect %.2f; "
                        "using container aspect %.2f", title->aspect,
                        title->container_aspect );
                 title->aspect = title->container_aspect;
                 hb_reduce( &title->pixel_aspect_width, &title->pixel_aspect_height,
-                           (int)(title->aspect * title->height), title->width );
+                           (int)(title->aspect * title->height + 0.5), title->width );
             }
         }
 
@@ -782,9 +864,21 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b )
     if( !audio || audio->config.in.bitrate != 0 )
     {
         /* not found or already done */
+        hb_buffer_close( &b );
         return;
     }
 
+    if ( audio->priv.scan_cache == NULL )
+        audio->priv.scan_cache = hb_fifo_init( 16, 16 );
+
+    if ( hb_fifo_size_bytes( audio->priv.scan_cache ) >= 4096 )
+    {
+        hb_buffer_t * tmp;
+        tmp = hb_fifo_get( audio->priv.scan_cache );
+        hb_buffer_close( &tmp );
+    }
+    hb_fifo_push( audio->priv.scan_cache, b );
+
     hb_work_object_t *w = hb_codec_decoder( audio->config.in.codec );
 
     if ( w == NULL || w->bsinfo == NULL )
@@ -797,6 +891,7 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b )
     hb_work_info_t info;
     w->audio = audio;
     w->codec_param = audio->config.in.codec_param;
+    b = hb_fifo_see( audio->priv.scan_cache );
     int ret = w->bsinfo( w, b, &info );
     if ( ret < 0 )
     {
@@ -810,9 +905,14 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b )
         /* didn't find any info */
         return;
     }
+    hb_fifo_flush( audio->priv.scan_cache );
+    hb_fifo_close( &audio->priv.scan_cache );
+
     audio->config.in.samplerate = info.rate;
     audio->config.in.bitrate = info.bitrate;
     audio->config.in.channel_layout = info.channel_layout;
+    audio->config.in.version = info.version;
+    audio->config.in.mode = info.mode;
     audio->config.flags.ac3 = info.flags;
 
     // update the audio description string based on the info we found
@@ -848,7 +948,10 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b )
     if ( w )
         free( w );
 
+    hb_fifo_flush( audio->priv.scan_cache );
+    hb_fifo_close( &audio->priv.scan_cache );
     hb_list_rem( title->list_audio, audio );
+    return;
 }
 
 /*