summaryrefslogtreecommitdiffstats
path: root/libhb/scan.c
diff options
context:
space:
mode:
authorvan <[email protected]>2008-05-31 17:00:42 +0000
committervan <[email protected]>2008-05-31 17:00:42 +0000
commitafbd06d8d6151b69bbb18adf83cfab8d680c3946 (patch)
tree4e7be731854c8b8db8f87934c301c60a9155387c /libhb/scan.c
parentd0550da569b56a71857c34463c5b030172d47291 (diff)
- support blu-ray, avchd & dvb x264
- support video files handled by ffmpeg (avi, mkv, mp4, etc.) git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1480 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/scan.c')
-rw-r--r--libhb/scan.c454
1 files changed, 130 insertions, 324 deletions
diff --git a/libhb/scan.c b/libhb/scan.c
index 674a1e35f..6834d4614 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -237,16 +237,15 @@ static void ScanFunc( void * _data )
static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
{
int i, npreviews = 0;
- hb_buffer_t * buf_ps, * buf_es, * buf_raw;
- hb_list_t * list_es, * list_raw;
- hb_libmpeg2_t * mpeg2;
+ hb_buffer_t * buf_ps, * buf_es;
+ hb_list_t * list_es;
int progressive_count = 0;
int interlaced_preview_count = 0;
- int last_ar = 0, ar16_count = 0, ar4_count = 0;
+ double last_ar = 0;
+ int ar16_count = 0, ar4_count = 0;
buf_ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
list_es = hb_list_init();
- list_raw = hb_list_init();
hb_log( "scan: decoding previews for title %d", title->index );
@@ -263,7 +262,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
{
if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / 11.0 ) )
{
- goto error;
+ continue;
}
}
else if (data->stream)
@@ -273,13 +272,17 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
* file and we need it to decode any previews. */
if (!hb_stream_seek(data->stream, (float) i / 11.0 ) )
{
- goto error;
+ continue;
}
}
hb_log( "scan: preview %d", i + 1 );
- mpeg2 = hb_libmpeg2_init();
+ 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->init( vid_decoder, NULL );
+ hb_buffer_t * vid_buf = NULL;
for( j = 0; j < 10240 ; j++ )
{
@@ -299,82 +302,76 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
goto skip_preview;
}
}
- hb_demux_ps( buf_ps, list_es, 0 );
+ if ( title->demuxer == HB_NULL_DEMUXER )
+ {
+ hb_demux_null( buf_ps, list_es, 0 );
+ }
+ else
+ {
+ hb_demux_ps( buf_ps, list_es, 0 );
+ }
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 ) )
+ if( buf_es->id == title->video_id && vid_buf == NULL )
{
- hb_libmpeg2_decode( mpeg2, buf_es, list_raw );
- int ar = hb_libmpeg2_clear_aspect_ratio( mpeg2 );
- if ( ar != 0 )
- {
- if ( ar != last_ar && last_ar != 0 )
- {
- hb_log( "aspect ratio changed from %d to %d",
- last_ar, ar );
- }
- switch ( ar )
- {
- case HB_ASPECT_BASE * 4 / 3:
- ++ar4_count;
- break;
- case HB_ASPECT_BASE * 16 / 9:
- ++ar16_count;
- break;
- default:
- hb_log( "unknown aspect ratio %d", ar );
- /* if the aspect is closer to 4:3 use that
- * otherwise use 16:9 */
- if ( ar < HB_ASPECT_BASE * 14 / 9 )
- {
- ++ar4_count;
- }
- else
- {
- ++ar16_count;
- }
- break;
- }
- }
- last_ar = ar;
+ vid_decoder->work( vid_decoder, &buf_es, &vid_buf );
}
else if( ! AllAudioOK( title ) )
{
LookForAudio( title, buf_es );
}
- hb_buffer_close( &buf_es );
-
- if( hb_list_count( list_raw ) && AllAudioOK( title ) )
- {
- /* We got a picture */
- break;
- }
+ if ( buf_es )
+ hb_buffer_close( &buf_es );
}
- if( hb_list_count( list_raw ) && AllAudioOK( title ) )
- {
+ if( vid_buf && AllAudioOK( title ) )
break;
- }
}
- if( !hb_list_count( list_raw ) )
+ if( ! vid_buf )
{
hb_log( "scan: could not get a decoded picture" );
continue;
}
/* Get size and rate infos */
- title->rate = 27000000;
- int ar;
- hb_libmpeg2_info( mpeg2, &title->width, &title->height,
- &title->rate_base, &ar );
- /* if we found mostly 4:3 previews use that as the aspect ratio otherwise
- use 16:9 */
- title->aspect = ar4_count > ar16_count ?
- HB_ASPECT_BASE * 4 / 3 : HB_ASPECT_BASE * 16 / 9;
+ hb_work_info_t vid_info;
+ vid_decoder->info( vid_decoder, &vid_info );
+ vid_decoder->close( vid_decoder );
+ free( vid_decoder );
+
+ title->width = vid_info.width;
+ title->height = vid_info.height;
+ title->rate = vid_info.rate;
+ title->rate_base = vid_info.rate_base;
+ if ( vid_info.aspect != 0 )
+ {
+ if ( vid_info.aspect != last_ar && last_ar != 0 )
+ {
+ hb_log( "aspect ratio changed from %g to %g",
+ last_ar, vid_info.aspect );
+ }
+ switch ( (int)vid_info.aspect )
+ {
+ case HB_ASPECT_BASE * 4 / 3:
+ ++ar4_count;
+ break;
+ case HB_ASPECT_BASE * 16 / 9:
+ ++ar16_count;
+ break;
+ default:
+ hb_log( "unknown aspect ratio %g", vid_info.aspect );
+ /* if the aspect is closer to 4:3 use that
+ * otherwise use 16:9 */
+ vid_info.aspect < HB_ASPECT_BASE * 14 / 9 ? ++ar4_count :
+ ++ar16_count;
+ break;
+ }
+ last_ar = vid_info.aspect;
+ }
if( title->rate_base == 1126125 )
{
@@ -421,18 +418,14 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
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 );
-
/* Check preview for interlacing artifacts */
- if( hb_detect_comb( buf_raw, title->width, title->height, 10, 30, 9, 10, 30, 9 ) )
+ 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);
interlaced_preview_count++;
@@ -444,7 +437,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
file_preview = fopen( filename, "w" );
if( file_preview )
{
- fwrite( buf_raw->data, title->width * title->height * 3 / 2,
+ fwrite( vid_buf->data, title->width * title->height * 3 / 2,
1, file_preview );
fclose( file_preview );
}
@@ -453,14 +446,14 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
hb_log( "scan: fopen failed (%s)", filename );
}
-#define Y buf_raw->data
+#define Y vid_buf->data
#define DARK 64
/* Detect black borders */
for( j = 0; j < title->width; j++ )
{
- for( k = 0; k < title->crop[0]; k++ )
+ for( k = 2; k < title->crop[0]; k++ )
if( Y[ k * title->width + j ] > DARK )
{
title->crop[0] = k;
@@ -493,13 +486,15 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
++npreviews;
skip_preview:
- while( ( buf_raw = hb_list_item( list_raw, 0 ) ) )
- {
- hb_list_rem( list_raw, buf_raw );
- hb_buffer_close( &buf_raw );
- }
+ if ( vid_buf )
+ hb_buffer_close( &vid_buf );
}
+ /* if we found mostly 4:3 previews use that as the aspect ratio otherwise
+ use 16:9 */
+ title->aspect = ar4_count > ar16_count ?
+ HB_ASPECT_BASE * 4 / 3 : HB_ASPECT_BASE * 16 / 9;
+
title->crop[0] = EVEN( title->crop[0] );
title->crop[1] = EVEN( title->crop[1] );
title->crop[2] = EVEN( title->crop[2] );
@@ -523,12 +518,6 @@ skip_preview:
title->detected_interlacing = 0;
}
- goto cleanup;
-
-error:
- npreviews = 0;
-
-cleanup:
hb_buffer_close( &buf_ps );
while( ( buf_es = hb_list_item( list_es, 0 ) ) )
{
@@ -536,236 +525,12 @@ cleanup:
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 );
if (data->dvd)
hb_dvd_stop( data->dvd );
return npreviews;
}
-static void update_audio_description( const char *codec, hb_audio_t *audio,
- int is_dolby )
-{
- hb_log( "scan: %s, rate=%dHz, bitrate=%d", codec, audio->config.in.samplerate,
- audio->config.in.bitrate );
-
- /* XXX */
- if ( is_dolby )
- {
- strcat( audio->config.lang.description, " (Dolby Surround)" );
- return;
- }
-
- char *desc = audio->config.lang.description +
- strlen( audio->config.lang.description );
- sprintf( desc, " (%d.%d ch)",
- HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->config.in.channel_layout) +
- HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->config.in.channel_layout),
- HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->config.in.channel_layout));
-}
-
-static int hb_setup_a52_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
- int i, rate, bitrate, flags;
-
- /* since AC3 frames don't line up with MPEG ES frames scan the
- * entire frame for an AC3 sync pattern. */
- for ( i = 0; i < b->size - 7; ++i )
- {
- if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) != 0 )
- {
- break;
- }
- }
- if ( i >= b->size - 7 )
- {
- /* didn't find AC3 sync */
- return 0;
- }
-
- audio->config.in.samplerate = rate;
- audio->config.in.bitrate = bitrate;
-
- switch( flags & A52_CHANNEL_MASK )
- {
- /* mono sources */
- case A52_MONO:
- case A52_CHANNEL1:
- case A52_CHANNEL2:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;
- break;
- /* stereo input */
- case A52_CHANNEL:
- case A52_STEREO:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
- break;
- /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */
- case A52_DOLBY:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_DOLBY;
- break;
- /* 3F/2R input */
- case A52_3F2R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;
- break;
- /* 3F/1R input */
- case A52_3F1R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;
- break;
- /* other inputs */
- case A52_3F:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;
- break;
- case A52_2F1R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;
- break;
- case A52_2F2R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;
- break;
- /* unknown */
- default:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
- }
-
- if (flags & A52_LFE)
- {
- audio->config.in.channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;
- }
-
- /* store the AC3 flags for future reference
- * This enables us to find out if we had a stereo or Dolby source later on
- * Store the ac3 flags in the public ac3flags property too, so we can access
- * it from the GUI
- */
- audio->config.flags.ac3 = audio->priv.config.a52.ac3flags = flags;
- update_audio_description( "AC3", audio, (flags & A52_CHANNEL_MASK) == A52_DOLBY );
- return 1;
-}
-
-static int hb_setup_dca_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
- int i, flags, rate, bitrate, frame_length;
- dca_state_t * state = dca_init( 0 );
-
- /* since DCA frames don't line up with MPEG ES frames scan the
- * entire frame for an DCA sync pattern. */
- for ( i = 0; i < b->size - 7; ++i )
- {
- if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate,
- &frame_length ) )
- {
- break;
- }
- }
- if ( i >= b->size - 7 )
- {
- /* didn't find DCA sync */
- return 0;
- }
-
- audio->config.in.samplerate = rate;
- audio->config.in.bitrate = bitrate;
- switch( flags & DCA_CHANNEL_MASK )
- {
- /* mono sources */
- case DCA_MONO:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;
- break;
- /* stereo input */
- case DCA_CHANNEL:
- case DCA_STEREO:
- case DCA_STEREO_SUMDIFF:
- case DCA_STEREO_TOTAL:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
- break;
- /* 3F/2R input */
- case DCA_3F2R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;
- break;
- /* 3F/1R input */
- case DCA_3F1R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;
- break;
- /* other inputs */
- case DCA_3F:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;
- break;
- case DCA_2F1R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;
- break;
- case DCA_2F2R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;
- break;
- case DCA_4F2R:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_4F2R;
- break;
- /* unknown */
- default:
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
- }
-
- if (flags & DCA_LFE)
- {
- audio->config.in.channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;
- }
-
- /* store the DCA flags for future reference
- * This enables us to find out if we had a stereo or Dolby source later on
- * store the dca flags in the public dcaflags property too, so we can access
- * it from the GUI
- */
- audio->config.flags.dca = audio->priv.config.dca.dcaflags = flags;
- update_audio_description( "DCA", audio, (flags & DCA_CHANNEL_MASK) == DCA_DOLBY );
- return 1;
-}
-
-static int hb_setup_pcm_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
- // LPCM doesn't have a sync pattern like AC3 or DCA but every
- // LPCM elementary stream packet starts with a 7 byte header
- // giving the characteristics of the stream.
- // See libhb/declpcm.c for a description of the LPCM header.
-
- static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 };
- static const int hdr2samplesize[] = { 16, 20, 24, 16 };
- static const int hdr2layout[] = {
- HB_INPUT_CH_LAYOUT_MONO, HB_INPUT_CH_LAYOUT_STEREO,
- HB_INPUT_CH_LAYOUT_2F1R, HB_INPUT_CH_LAYOUT_2F2R,
- HB_INPUT_CH_LAYOUT_3F2R, HB_INPUT_CH_LAYOUT_4F2R,
- HB_INPUT_CH_LAYOUT_STEREO, HB_INPUT_CH_LAYOUT_STEREO,
- };
-
- int nchannels = ( b->data[4] & 7 ) + 1;
- int sample_size = hdr2samplesize[b->data[4] >> 6];
-
- int rate = hdr2samplerate[ ( b->data[4] >> 4 ) & 0x3 ];
- int bitrate = rate * sample_size * nchannels;
-
- audio->config.in.samplerate = rate;
- audio->config.in.bitrate = bitrate;
- audio->config.in.channel_layout = hdr2layout[nchannels - 1];
- update_audio_description( "LPCM", audio, 0 );
- return 1;
-}
-
-static int hb_setup_mpg_audio( hb_audio_t *audio, hb_buffer_t *b )
-{
- /* XXX
- * This is a placeholder to get the audio sample rate set.
- * It should be replaced by something that extracts the correct info from
- * the mpeg audio bitstream.
- */
- audio->config.in.samplerate = 48000;
- audio->config.in.bitrate = 384000;
- audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
- update_audio_description( "MPGA", audio, 0 );
- return 1;
-}
-
/*
* This routine is called for every frame from a non-video elementary stream.
* These are a mix of audio & subtitle streams, some of which we want & some
@@ -804,29 +569,70 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b )
return;
}
- switch ( audio->config.in.codec )
- {
- case HB_ACODEC_AC3:
- hb_setup_a52_audio( audio, b );
- break;
+ hb_work_object_t *w = hb_codec_decoder( audio->config.in.codec );
- case HB_ACODEC_DCA:
- hb_setup_dca_audio( audio, b );
- break;
-
- case HB_ACODEC_LPCM:
- hb_setup_pcm_audio( audio, b );
- break;
+ if ( w == NULL || w->bsinfo == NULL )
+ {
+ hb_log( "Internal error in scan: unhandled audio type %d for id 0x%x",
+ audio->config.in.codec, audio->id );
+ goto drop_audio;
+ }
- case HB_ACODEC_MPGA:
- hb_setup_mpg_audio( audio, b );
- break;
+ hb_work_info_t info;
+ w->audio = audio;
+ w->codec_param = audio->config.in.codec_param;
+ int ret = w->bsinfo( w, b, &info );
+ if ( ret < 0 )
+ {
+ hb_log( "no info on audio type %d/0x%x for id 0x%x",
+ audio->config.in.codec, audio->config.in.codec_param,
+ audio->id );
+ goto drop_audio;
+ }
+ if ( !info.bitrate )
+ {
+ /* didn't find any info */
+ return;
+ }
+ audio->config.in.samplerate = info.rate;
+ audio->config.in.bitrate = info.bitrate;
+ audio->config.in.channel_layout = info.channel_layout;
+ audio->config.flags.ac3 = info.flags;
- default:
- hb_log( "Internal error in scan: unhandled audio type %d for 0x%x",
- audio->config.in.codec, audio->id );
- break;
+ // update the audio description string based on the info we found
+ if ( audio->config.flags.ac3 & AUDIO_F_DOLBY )
+ {
+ strcat( audio->config.lang.description, " (Dolby Surround)" );
}
+ else
+ {
+ int layout = audio->config.in.channel_layout;
+ char *desc = audio->config.lang.description +
+ strlen( audio->config.lang.description );
+ sprintf( desc, " (%d.%d ch)",
+ HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(layout) +
+ HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(layout),
+ HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(layout) );
+ }
+
+ hb_log( "scan: audio 0x%x: %s, rate=%dHz, bitrate=%d %s", audio->id,
+ info.name, audio->config.in.samplerate, audio->config.in.bitrate,
+ audio->config.lang.description );
+
+ free( w );
+ return;
+
+ // We get here if there's no hope of finding info on an audio bitstream,
+ // either because we don't have a decoder (or a decoder with a bitstream
+ // info proc) or because the decoder's info proc said that the stream
+ // wasn't something it could handle. Delete the item from the title's
+ // audio list so we won't keep reading packets while trying to get its
+ // bitstream info.
+ drop_audio:
+ if ( w )
+ free( w );
+
+ hb_list_rem( title->list_audio, audio );
}
/*