diff options
Diffstat (limited to 'libhb/scan.c')
-rw-r--r-- | libhb/scan.c | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/libhb/scan.c b/libhb/scan.c new file mode 100644 index 000000000..daf8da27e --- /dev/null +++ b/libhb/scan.c @@ -0,0 +1,522 @@ +/* $Id: scan.c,v 1.52 2005/11/25 15:05:25 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" +#include "a52dec/a52.h" + +typedef struct +{ + hb_handle_t * h; + + char * path; + int title_index; + hb_list_t * list_title; + + hb_dvd_t * dvd; + +} hb_scan_t; + +static void ScanFunc( void * ); +static int DecodePreviews( hb_scan_t *, hb_title_t * title ); +static void LookForAC3( hb_title_t * title, hb_buffer_t * b ); +static int AllAC3OK( hb_title_t * title ); + +hb_thread_t * hb_scan_init( hb_handle_t * handle, const char * path, + int title_index, hb_list_t * list_title ) +{ + hb_scan_t * data = calloc( sizeof( hb_scan_t ), 1 ); + + data->h = handle; + data->path = strdup( path ); + data->title_index = title_index; + data->list_title = list_title; + + return hb_thread_init( "scan", ScanFunc, data, HB_NORMAL_PRIORITY ); +} + +static void ScanFunc( void * _data ) +{ + hb_scan_t * data = (hb_scan_t *) _data; + hb_title_t * title; + int i; + + /* Try to open the path as a DVD. If it fails, try as a file */ + hb_log( "scan: trying to open with libdvdread" ); + if( ( data->dvd = hb_dvd_init( data->path ) ) ) + { + hb_log( "scan: DVD has %d title(s)", + hb_dvd_title_count( data->dvd ) ); + if( data->title_index ) + { + /* Scan this title only */ + hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, + data->title_index ) ); + } + else + { + /* Scan all titles */ + for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ ) + { + hb_list_add( data->list_title, + hb_dvd_title_scan( data->dvd, i + 1 ) ); + } + } + } + else + { + /* Open as a VOB file */ + FILE * file; + hb_log( "scan: trying to open as VOB file" ); + file = fopen( data->path, "rb" ); + if( file ) + { + /* XXX */ + fclose( file ); + } + else + { + hb_log( "scan: fopen failed" ); + return; + } + } + + for( i = 0; i < hb_list_count( data->list_title ); ) + { + 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 ) + { + hb_log( "scan: title %d is duplicate with title %d", + title->index, title_tmp->index ); + hb_list_rem( data->list_title, title ); + free( title ); + continue; + } + +#define p state.param.scanning + /* Update the UI */ + state.state = HB_STATE_SCANNING; + p.title_cur = title->index; + p.title_count = hb_dvd_title_count( data->dvd ); + hb_set_state( data->h, &state ); +#undef p + + /* Decode previews */ + if( !DecodePreviews( data, title ) ) + { + /* TODO: free things */ + hb_list_rem( data->list_title, title ); + continue; + } + + /* Make sure we found AC3 rates and bitrates */ + for( j = 0; j < hb_list_count( title->list_audio ); ) + { + audio = hb_list_item( title->list_audio, j ); + if( audio->codec == HB_ACODEC_AC3 && + !audio->bitrate ) + { + hb_list_rem( title->list_audio, audio ); + free( audio ); + continue; + } + j++; + } + + /* Do we still have audio */ + if( !hb_list_count( title->list_audio ) ) + { + hb_list_rem( data->list_title, title ); + free( title ); + continue; + } + + i++; + } + + /* Init jobs templates */ + for( i = 0; i < hb_list_count( data->list_title ); i++ ) + { + hb_job_t * job; + + title = hb_list_item( data->list_title, i ); + job = calloc( sizeof( hb_job_t ), 1 ); + title->job = job; + + job->title = title; + + /* Set defaults settings */ + job->chapter_start = 1; + job->chapter_end = hb_list_count( title->list_chapter ); + + /* Autocrop by default. Gnark gnark */ + memcpy( job->crop, title->crop, 4 * sizeof( int ) ); + + if( title->aspect == 16 ) + { + hb_reduce( &job->pixel_aspect_width, &job->pixel_aspect_height, + 16 * title->height, 9 * title->width ); + } + else + { + hb_reduce( &job->pixel_aspect_width, &job->pixel_aspect_height, + 4 * title->height, 3 * title->width ); + } + + job->width = title->width - job->crop[2] - job->crop[3]; +// job->height = title->height - job->crop[0] - job->crop[1]; + hb_fix_aspect( job, HB_KEEP_WIDTH ); + if( job->height > title->height - job->crop[0] - job->crop[1] ) + { + job->height = title->height - job->crop[0] - job->crop[1]; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + } + + hb_log( "scan: title (%d) job->width:%d, job->height:%d", + i,job->width, job->height ); + + job->keep_ratio = 1; + + job->vcodec = HB_VCODEC_FFMPEG; + job->vquality = -1.0; + job->vbitrate = 1000; + job->pass = 0; + job->vrate = title->rate; + job->vrate_base = title->rate_base; + + job->audios[0] = 0; + job->audios[1] = -1; + + job->acodec = HB_ACODEC_FAAC; + job->abitrate = 128; + job->arate = 44100; + + job->subtitle = -1; + + job->mux = HB_MUX_MP4; + } + + if( data->dvd ) + { + hb_dvd_close( &data->dvd ); + } +} + +/*********************************************************************** + * DecodePreviews + *********************************************************************** + * Decode 10 pictures for the given title. + * It assumes that data->reader and data->vts have successfully been + * DVDOpen()ed and ifoOpen()ed. + **********************************************************************/ +static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) +{ + int i, ret; + hb_buffer_t * buf_ps, * buf_es, * buf_raw; + hb_list_t * list_es, * list_raw; + hb_libmpeg2_t * mpeg2; + + buf_ps = hb_buffer_init( 2048 ); + list_es = hb_list_init(); + list_raw = hb_list_init(); + + hb_log( "scan: decoding previews for title %d", title->index ); + + hb_dvd_start( data->dvd, title->index, 1 ); + + for( i = 0; i < 10; i++ ) + { + int j, k; + FILE * file_preview; + char filename[1024]; + + if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / 11.0 ) ) + { + goto error; + } + + hb_log( "scan: preview %d", i + 1 ); + + mpeg2 = hb_libmpeg2_init(); + + for( j = 0; j < 10240 ; j++ ) + { + if( !hb_dvd_read( data->dvd, buf_ps ) ) + { + goto error; + } + hb_demux_ps( buf_ps, list_es ); + + while( ( buf_es = hb_list_item( list_es, 0 ) ) ) + { + hb_list_rem( list_es, buf_es ); + if( buf_es->id == 0xE0 && !hb_list_count( list_raw ) ) + { + hb_libmpeg2_decode( mpeg2, buf_es, list_raw ); + } + else if( !i ) + { + LookForAC3( title, buf_es ); + } + hb_buffer_close( &buf_es ); + + if( hb_list_count( list_raw ) && + ( i || AllAC3OK( title ) ) ) + { + /* We got a picture */ + break; + } + } + + if( hb_list_count( list_raw ) && + ( i || AllAC3OK( title ) ) ) + { + break; + } + } + + if( !hb_list_count( list_raw ) ) + { + hb_log( "scan: could not get a decoded picture" ); + goto error; + } + + if( !i ) + { + /* Get size and rate infos */ + title->rate = 27000000; + hb_libmpeg2_info( mpeg2, &title->width, &title->height, + &title->rate_base ); + title->crop[0] = title->crop[1] = title->height / 2; + title->crop[2] = title->crop[3] = title->width / 2; + } + + hb_libmpeg2_close( &mpeg2 ); + + while( ( buf_es = hb_list_item( list_es, 0 ) ) ) + { + hb_list_rem( list_es, buf_es ); + hb_buffer_close( &buf_es ); + } + + buf_raw = hb_list_item( list_raw, 0 ); + + hb_get_tempory_filename( data->h, filename, "%x%d", + (int) title, i ); + + file_preview = fopen( filename, "w" ); + if( file_preview ) + { + fwrite( buf_raw->data, title->width * title->height * 3 / 2, + 1, file_preview ); + fclose( file_preview ); + } + else + { + hb_log( "scan: fopen failed (%s)", filename ); + } + +#define Y buf_raw->data +#define DARK 64 + + /* Detect black borders */ + + for( j = 0; j < title->width; j++ ) + { + for( k = 0; k < title->crop[0]; k++ ) + if( Y[ k * title->width + j ] > DARK ) + { + title->crop[0] = k; + break; + } + for( k = 0; k < title->crop[1]; k++ ) + if( Y[ ( title->height - k - 1 ) * + title->width + j ] > DARK ) + { + title->crop[1] = k; + break; + } + } + for( j = 0; j < title->height; j++ ) + { + for( k = 0; k < title->crop[2]; k++ ) + if( Y[ j * title->width + k ] > DARK ) + { + title->crop[2] = k; + break; + } + for( k = 0; k < title->crop[3]; k++ ) + if( Y[ j * title->width + + title->width - k - 1 ] > DARK ) + { + title->crop[3] = k; + break; + } + } + + while( ( buf_raw = hb_list_item( list_raw, 0 ) ) ) + { + hb_list_rem( list_raw, buf_raw ); + hb_buffer_close( &buf_raw ); + } + } + + title->crop[0] = EVEN( title->crop[0] ); + title->crop[1] = EVEN( title->crop[1] ); + title->crop[2] = EVEN( title->crop[2] ); + title->crop[3] = EVEN( title->crop[3] ); + + hb_log( "scan: %dx%d, %.3f fps, autocrop = %d/%d/%d/%d", + title->width, title->height, (float) title->rate / + (float) title->rate_base, title->crop[0], title->crop[1], + title->crop[2], title->crop[3] ); + + ret = 1; + goto cleanup; + +error: + ret = 0; + +cleanup: + hb_buffer_close( &buf_ps ); + while( ( buf_es = hb_list_item( list_es, 0 ) ) ) + { + hb_list_rem( list_es, buf_es ); + hb_buffer_close( &buf_es ); + } + hb_list_close( &list_es ); + while( ( buf_raw = hb_list_item( list_raw, 0 ) ) ) + { + hb_list_rem( list_raw, buf_raw ); + hb_buffer_close( &buf_raw ); + } + hb_list_close( &list_raw ); + hb_dvd_stop( data->dvd ); + return ret; +} + +static void LookForAC3( hb_title_t * title, hb_buffer_t * b ) +{ + int i; + int flags; + int rate; + int bitrate; + + /* Figure out if this is a AC3 buffer for a known track */ + hb_audio_t * audio = NULL; + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( audio->codec == HB_ACODEC_AC3 && + audio->id == b->id ) + { + break; + } + else + { + audio = NULL; + } + } + if( !audio ) + { + return; + } + + if( audio->bitrate ) + { + /* Already done for this track */ + return; + } + + for( i = 0; i < b->size - 7; i++ ) + { + if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) ) + { + hb_log( "scan: rate=%dHz, bitrate=%d", rate, bitrate ); + audio->rate = rate; + audio->bitrate = bitrate; + switch( flags & A52_CHANNEL_MASK ) + { + case A52_MONO: + case A52_CHANNEL1: + case A52_CHANNEL2: + audio->channels = 1; + break; + case A52_STEREO: + case A52_DOLBY: + case A52_CHANNEL: + audio->channels = 2; + break; + case A52_3F: + case A52_2F1R: + audio->channels = 3; + break; + case A52_3F1R: + case A52_2F2R: + audio->channels = 4; + break; + case A52_3F2R: + audio->channels = 5; + break; + } + + if (flags & A52_LFE) { + audio->lfechannels = 1; + } else { + audio->lfechannels = 0; + } + + /* store the AC3 tags for future reference + This enables us to find out if we had a stereo or Dolby source later on */ + audio->ac3flags = flags; + + /* XXX */ + sprintf( audio->lang + strlen( audio->lang ), + " (%d.%d ch)", audio->channels, audio->lfechannels ); + break; + } + } +} + +static int AllAC3OK( hb_title_t * title ) +{ + int i; + hb_audio_t * audio; + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( audio->codec == HB_ACODEC_AC3 && + !audio->bitrate ) + { + return 0; + } + } + + return 1; +} |