OSDN Git Service

Another minor step on the way back to Solaris compiles - not linking as yet.
[handbrake-jp/handbrake-jp-git.git] / libhb / encfaac.c
index d46e8ae..c955199 100644 (file)
@@ -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: <http://handbrake.m0k.org/>.
+   Homepage: <http://handbrake.fr/>.
    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);
+
+    /* 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( job->arate, pv->out_discrete_channels, &pv->input_samples,
-                           &pv->output_bytes );
+    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,39 +114,44 @@ 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 (pv->out_discrete_channels == 6) {
-               /* we are preserving 5.1 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 */
-               /* 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 (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;
 }
@@ -119,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;
+    }
 }
 
 /***********************************************************************
@@ -134,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 ) )
     {
@@ -143,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;
 }
 
 /***********************************************************************
@@ -181,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;
 
@@ -191,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;
 }