X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fencfaac.c;h=c955199d062a7de1c52616b9767b48a8954e6ec3;hb=033e32de9c380f54c7d1362a3979da205ebc3a29;hp=a5b704f4c0732ac621556718170f88de7d8ed920;hpb=cdba71d1dca214142fdcca4c52f7672252752c2e;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/encfaac.c b/libhb/encfaac.c index a5b704f4..c955199d 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -1,80 +1,159 @@ /* $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" #include "faac.h" -struct hb_work_object_s +struct hb_work_private_s { - HB_WORK_COMMON; - hb_job_t * job; - hb_audio_t * audio; faacEncHandle * faac; 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; }; -/*********************************************************************** - * Local prototypes - **********************************************************************/ -static void Close( hb_work_object_t ** _w ); -static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ); +int encfaacInit( hb_work_object_t *, hb_job_t * ); +int encfaacWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); +void encfaacClose( hb_work_object_t * ); + +hb_work_object_t hb_encfaac = +{ + WORK_ENCFAAC, + "AAC encoder (libfaac)", + encfaacInit, + encfaacWork, + 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 *********************************************************************** * **********************************************************************/ -hb_work_object_t * hb_work_encfaac_init( hb_job_t * job, hb_audio_t * audio ) +int encfaacInit( hb_work_object_t * w, hb_job_t * job ) { - hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); + hb_audio_t * audio = w->audio; faacEncConfigurationPtr cfg; - w->name = strdup( "AAC encoder (libfaac)" ); - w->work = Work; - w->close = Close; - - w->job = job; - w->audio = audio; - - w->faac = faacEncOpen( job->arate, 2, &w->input_samples, - &w->output_bytes ); - w->buf = malloc( w->input_samples * sizeof( float ) ); - - cfg = faacEncGetCurrentConfiguration( w->faac ); + uint8_t * bytes; + unsigned long length; + + w->private_data = pv; + + pv->job = job; + + /* 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( !faacEncSetConfiguration( w->faac, cfg ) ) + + 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( w->faac, &audio->config.faac.decinfo, - &audio->config.faac.size ) < 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 ); - w->list = hb_list_init(); - w->pts = -1; + pv->list = hb_list_init(); - return w; + return 0; } /*********************************************************************** @@ -82,18 +161,32 @@ hb_work_object_t * hb_work_encfaac_init( hb_job_t * job, hb_audio_t * audio ) *********************************************************************** * **********************************************************************/ -static void Close( hb_work_object_t ** _w ) +void encfaacClose( hb_work_object_t * w ) { - hb_work_object_t * w = *_w; - - faacEncClose( w->faac ); - free( w->buf ); - hb_list_empty( &w->list ); - free( w->audio->config.faac.decinfo ); + hb_work_private_t * pv = w->private_data; + 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( w->name ); - free( w ); - *_w = NULL; + free( pv ); + w->private_data = NULL; + } } /*********************************************************************** @@ -103,41 +196,75 @@ static void Close( hb_work_object_t ** _w ) **********************************************************************/ static hb_buffer_t * Encode( hb_work_object_t * w ) { - hb_buffer_t * buf; - uint64_t pts; - int pos; + hb_work_private_t * pv = w->private_data; - if( hb_list_bytes( w->list ) < w->input_samples * sizeof( float ) ) + if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) { /* Need more data */ return NULL; } - hb_list_getbytes( w->list, w->buf, w->input_samples * sizeof( float ), + 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( w->output_bytes ); - buf->start = pts + 90000 * pos / 2 / sizeof( float ) / w->job->arate; - buf->stop = buf->start + 90000 * w->input_samples / w->job->arate / 2; - buf->size = faacEncEncode( w->faac, (int32_t *) w->buf, - w->input_samples, buf->data, w->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; } /*********************************************************************** @@ -145,12 +272,23 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) *********************************************************************** * **********************************************************************/ -static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, +int encfaacWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { + hb_work_private_t * pv = w->private_data; hb_buffer_t * buf; - hb_list_add( w->list, *buf_in ); + 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; *buf_out = buf = Encode( w ); @@ -160,7 +298,7 @@ static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, buf->next = Encode( w ); buf = buf->next; } - + return HB_WORK_OK; }