X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fencfaac.c;h=c955199d062a7de1c52616b9767b48a8954e6ec3;hb=033e32de9c380f54c7d1362a3979da205ebc3a29;hp=5545f9ebf0f197a229710c14b45e2a78d875c494;hpb=c7487f45ee5ffe1116ef1394be2cb7eed677c3ca;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/encfaac.c b/libhb/encfaac.c index 5545f9eb..c955199d 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -1,7 +1,7 @@ /* $Id: encfaac.c,v 1.13 2005/03/03 17:21:57 titer Exp $ This file is part of the HandBrake source code. - Homepage: . + Homepage: . It may be used under the terms of the GNU General Public License. */ #include "hb.h" @@ -16,12 +16,11 @@ struct hb_work_private_s unsigned long input_samples; unsigned long output_bytes; uint8_t * buf; - + uint8_t * obuf; hb_list_t * list; int64_t pts; - + int64_t framedur; int out_discrete_channels; - }; int encfaacInit( hb_work_object_t *, hb_job_t * ); @@ -37,6 +36,21 @@ hb_work_object_t hb_encfaac = encfaacClose }; +static const int valid_rates[] = +{ + 22050, 24000, 32000, 44100, 48000, 0 +}; + +static int find_samplerate( int rate ) +{ + int i; + + for ( i = 0; valid_rates[i] && rate > valid_rates[i]; ++i ) + { + } + return i; +} + /*********************************************************************** * hb_work_encfaac_init *********************************************************************** @@ -45,6 +59,7 @@ hb_work_object_t hb_encfaac = int encfaacInit( hb_work_object_t * w, hb_job_t * job ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); + hb_audio_t * audio = w->audio; faacEncConfigurationPtr cfg; uint8_t * bytes; unsigned long length; @@ -54,17 +69,42 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) pv->job = job; /* pass the number of channels used into the private work data */ - pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown); + pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown); - pv->faac = faacEncOpen( job->arate, pv->out_discrete_channels, &pv->input_samples, - &pv->output_bytes ); + /* if the sample rate is 'auto' and that has given us an invalid output */ + /* rate, map it to the next highest output rate or 48K if above the highest. */ + int rate_index = find_samplerate(audio->config.out.samplerate); + if ( audio->config.out.samplerate != valid_rates[rate_index] ) + { + int rate = valid_rates[valid_rates[rate_index]? rate_index : rate_index - 1]; + hb_log( "encfaac changing output samplerate from %d to %d", + audio->config.out.samplerate, rate ); + audio->config.out.samplerate = rate; + + /* if the new rate is over the max bandwidth per channel limit */ + /* lower the bandwidth. */ + double bw = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; + if ( bw > (double)rate * (6144./1024.) ) + { + int newbr = (double)rate * (6.144/1024.) * pv->out_discrete_channels; + hb_log( "encfaac changing output bitrate from %d to %d", + audio->config.out.bitrate, newbr ); + audio->config.out.bitrate = newbr; + } + } + + pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels, + &pv->input_samples, &pv->output_bytes ); pv->buf = malloc( pv->input_samples * sizeof( float ) ); - + pv->obuf = malloc( pv->output_bytes ); + pv->framedur = 90000LL * pv->input_samples / + ( audio->config.out.samplerate * pv->out_discrete_channels ); + cfg = faacEncGetCurrentConfiguration( pv->faac ); cfg->mpegVersion = MPEG4; cfg->aacObjectType = LOW; cfg->allowMidside = 1; - + if (pv->out_discrete_channels == 6) { /* we are preserving 5.1 audio into 6-channel AAC, so indicate that we have an lfe channel */ @@ -74,12 +114,12 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) } cfg->useTns = 0; - cfg->bitRate = job->abitrate * 1000 / pv->out_discrete_channels; /* Per channel */ + cfg->bitRate = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */ cfg->bandWidth = 0; cfg->outputFormat = 0; cfg->inputFormat = FAAC_INPUT_FLOAT; - - if (w->amixdown == HB_AMIXDOWN_6CH && w->source_acodec == HB_ACODEC_AC3) + + if (audio->config.out.mixdown == HB_AMIXDOWN_6CH && audio->config.in.codec == HB_ACODEC_AC3) { /* we are preserving 5.1 AC-3 audio into 6-channel AAC, and need to re-map the output of deca52 into our own mapping - the mapping @@ -93,7 +133,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) cfg->channel_map[4] = 5; cfg->channel_map[5] = 0; } - + if( !faacEncSetConfiguration( pv->faac, cfg ) ) { hb_log( "faacEncSetConfiguration failed" ); @@ -112,7 +152,6 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) free( bytes ); pv->list = hb_list_init(); - pv->pts = -1; return 0; } @@ -125,11 +164,29 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) void encfaacClose( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; - faacEncClose( pv->faac ); - free( pv->buf ); - hb_list_empty( &pv->list ); - free( pv ); - w->private_data = NULL; + if ( pv ) + { + if ( pv->faac ) + { + faacEncClose( pv->faac ); + pv->faac = NULL; + } + if ( pv->buf ) + { + free( pv->buf ); + pv->buf = NULL; + } + if ( pv->obuf ) + { + free( pv->obuf ); + pv->obuf = NULL; + } + if ( pv->list ) + hb_list_empty( &pv->list ); + + free( pv ); + w->private_data = NULL; + } } /*********************************************************************** @@ -140,8 +197,6 @@ void encfaacClose( hb_work_object_t * w ) static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; - hb_buffer_t * buf; - uint64_t pts, pos; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { @@ -149,31 +204,67 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) return NULL; } + uint64_t pts, pos; hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos ); + int size = faacEncEncode( pv->faac, (int32_t *)pv->buf, pv->input_samples, + pv->obuf, pv->output_bytes ); - buf = hb_buffer_init( pv->output_bytes ); - buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / pv->job->arate; - buf->stop = buf->start + 90000 * pv->input_samples / pv->job->arate / pv->out_discrete_channels; - buf->size = faacEncEncode( pv->faac, (int32_t *) pv->buf, - pv->input_samples, buf->data, pv->output_bytes ); - buf->key = 1; - - if( !buf->size ) + // AAC needs four frames before it can start encoding so we'll get nothing + // on the first three calls to the encoder. + if ( size > 0 ) { - /* Encoding was successful but we got no data. Try to encode - more */ - hb_buffer_close( &buf ); - return Encode( w ); + hb_buffer_t * buf = hb_buffer_init( size ); + memcpy( buf->data, pv->obuf, size ); + buf->size = size; + buf->start = pv->pts; + pv->pts += pv->framedur; + buf->stop = pv->pts; + buf->frametype = HB_FRAME_AUDIO; + return buf; } - else if( buf->size < 0 ) + return NULL; +} + +static hb_buffer_t *Flush( hb_work_object_t *w, hb_buffer_t *bufin ) +{ + hb_work_private_t *pv = w->private_data; + + // pad whatever data we have out to four input frames. + int nbytes = hb_list_bytes( pv->list ); + int pad = pv->input_samples * sizeof(float) * 4 - nbytes; + if ( pad > 0 ) { - hb_log( "faacEncEncode failed" ); - hb_buffer_close( &buf ); - return NULL; + hb_buffer_t *tmp = hb_buffer_init( pad ); + memset( tmp->data, 0, pad ); + hb_list_add( pv->list, tmp ); } - return buf; + // There are up to three frames buffered in the encoder plus one + // in our list buffer so four calls to Encode should get them all. + hb_buffer_t *bufout = NULL, *buf = NULL; + while ( hb_list_bytes( pv->list ) >= pv->input_samples * sizeof(float) ) + { + hb_buffer_t *b = Encode( w ); + if ( b ) + { + if ( bufout == NULL ) + { + bufout = b; + } + else + { + buf->next = b; + } + buf = b; + } + } + // add the eof marker to the end of our buf chain + if ( buf ) + buf->next = bufin; + else + bufout = bufin; + return bufout; } /*********************************************************************** @@ -187,6 +278,16 @@ int encfaacWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_buffer_t * buf; + if ( (*buf_in)->size <= 0 ) + { + // EOF on input. Finish encoding what we have buffered then send + // it & the eof downstream. + + *buf_out = Flush( w, *buf_in ); + *buf_in = NULL; + return HB_WORK_DONE; + } + hb_list_add( pv->list, *buf_in ); *buf_in = NULL; @@ -197,7 +298,7 @@ int encfaacWork( hb_work_object_t * w, hb_buffer_t ** buf_in, buf->next = Encode( w ); buf = buf->next; } - + return HB_WORK_OK; }