X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fencfaac.c;h=c955199d062a7de1c52616b9767b48a8954e6ec3;hb=033e32de9c380f54c7d1362a3979da205ebc3a29;hp=8e2bd43559c224931ba804aac1dcaeab653891e3;hpb=4c8043dc840793d01efa2edb1668c54a520c2e9a;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/encfaac.c b/libhb/encfaac.c index 8e2bd435..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,9 +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 * ); @@ -34,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 *********************************************************************** @@ -42,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; @@ -50,35 +68,90 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) pv->job = job; - pv->faac = faacEncOpen( job->arate, 2, &pv->input_samples, - &pv->output_bytes ); + /* pass the number of channels used into the private work data */ + pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown); + + /* 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; - cfg->useLfe = 0; + + if (pv->out_discrete_channels == 6) { + /* we are preserving 5.1 audio into 6-channel AAC, + so indicate that we have an lfe channel */ + cfg->useLfe = 1; + } else { + cfg->useLfe = 0; + } + cfg->useTns = 0; - cfg->bitRate = job->abitrate * 500; /* 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 (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 + below is the default mapping expected by QuickTime */ + /* DTS output from libdca is already in the right mapping for QuickTime */ + /* This doesn't seem to be correct for VLC on Linux */ + cfg->channel_map[0] = 2; + cfg->channel_map[1] = 1; + cfg->channel_map[2] = 3; + cfg->channel_map[3] = 4; + cfg->channel_map[4] = 5; + cfg->channel_map[5] = 0; + } + if( !faacEncSetConfiguration( pv->faac, cfg ) ) { hb_log( "faacEncSetConfiguration failed" ); + *job->die = 1; + return 0; } if( faacEncGetDecoderSpecificInfo( pv->faac, &bytes, &length ) < 0 ) { hb_log( "faacEncGetDecoderSpecificInfo failed" ); + *job->die = 1; + return 0; } memcpy( w->config->aac.bytes, bytes, length ); w->config->aac.length = length; free( bytes ); pv->list = hb_list_init(); - pv->pts = -1; return 0; } @@ -91,9 +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 ); + 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; + } } /*********************************************************************** @@ -104,9 +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; - int pos; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { @@ -114,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 / 2 / sizeof( float ) / pv->job->arate; - buf->stop = buf->start + 90000 * pv->input_samples / pv->job->arate / 2; - 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; } /*********************************************************************** @@ -152,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; @@ -162,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; }