faad.c 12 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * decoder.c: AAC decoder using libfaad2
 *****************************************************************************
 * Copyright (C) 2001, 2003 VideoLAN
Gildas Bazin's avatar
 
Gildas Bazin committed
5
 * $Id: faad.c,v 1.8 2003/12/12 23:15:40 gbazin Exp $
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
Gildas Bazin's avatar
 
Gildas Bazin committed
8
 *          Gildas Bazin <gbazin@netcourrier.com>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

25
#include <vlc/vlc.h>
26 27 28 29 30 31 32 33 34
#include <vlc/aout.h>
#include <vlc/decoder.h>

#include <faad.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open( vlc_object_t * );
35
static void Close( vlc_object_t * );
36 37 38

vlc_module_begin();
    set_description( _("AAC audio decoder (using libfaad2)") );
39
    set_capability( "decoder", 100 );
40
    set_callbacks( Open, Close );
41 42 43 44 45
vlc_module_end();

/****************************************************************************
 * Local prototypes
 ****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
46
static aout_buffer_t *DecodeBlock( decoder_t *, block_t ** );
Gildas Bazin's avatar
 
Gildas Bazin committed
47 48 49 50
static void DoReordering( decoder_t *, uint32_t *, uint32_t *, int, int,
                          uint32_t * );

#define MAX_CHANNEL_POSITIONS 9
51 52 53 54 55 56 57

struct decoder_sys_t
{
    /* faad handler */
    faacDecHandle *hfaad;

    /* samples */
Gildas Bazin's avatar
 
Gildas Bazin committed
58
    audio_date_t date;
59 60

    /* temporary buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
61 62 63
    uint8_t *p_buffer;
    int     i_buffer;
    int     i_buffer_size;
64

Gildas Bazin's avatar
 
Gildas Bazin committed
65 66
    /* Channel positions of the current stream (for re-ordering) */
    uint32_t pi_channel_positions[MAX_CHANNEL_POSITIONS];
67 68
};

Gildas Bazin's avatar
 
Gildas Bazin committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
static const uint32_t pi_channels_in[MAX_CHANNEL_POSITIONS] =
    { FRONT_CHANNEL_CENTER, FRONT_CHANNEL_LEFT, FRONT_CHANNEL_RIGHT,
      SIDE_CHANNEL_LEFT, SIDE_CHANNEL_RIGHT,
      BACK_CHANNEL_LEFT, BACK_CHANNEL_RIGHT,
      BACK_CHANNEL_CENTER, LFE_CHANNEL };
static const uint32_t pi_channels_out[MAX_CHANNEL_POSITIONS] =
    { AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
      AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
      AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
      AOUT_CHAN_REARCENTER, AOUT_CHAN_LFE };
static const uint32_t pi_channels_ordered[MAX_CHANNEL_POSITIONS] =
    { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
      AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
      AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
      AOUT_CHAN_CENTER, AOUT_CHAN_REARCENTER, AOUT_CHAN_LFE
    };

86
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
87
 * OpenDecoder: probe the decoder and return score
88
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
89
static int Open( vlc_object_t *p_this )
90
{
Gildas Bazin's avatar
 
Gildas Bazin committed
91
    decoder_t *p_dec = (decoder_t*)p_this;
92 93 94
    decoder_sys_t *p_sys = p_dec->p_sys;
    faacDecConfiguration *cfg;

Gildas Bazin's avatar
 
Gildas Bazin committed
95
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','4','a') )
96
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
97 98 99 100 101 102 103 104 105
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_dec->p_sys = p_sys =
          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return VLC_EGENERIC;
106 107 108 109 110 111 112 113 114
    }

    /* Open a faad context */
    if( ( p_sys->hfaad = faacDecOpen() ) == NULL )
    {
        msg_Err( p_dec, "Cannot initialize faad" );
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
115 116 117 118 119 120
    /* Misc init */
    aout_DateSet( &p_sys->date, 0 );
    p_dec->fmt_out.i_cat = AUDIO_ES;
    p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
    p_dec->pf_decode_audio = DecodeBlock;

Gildas Bazin's avatar
 
Gildas Bazin committed
121 122 123
    p_dec->fmt_out.audio.i_physical_channels =
        p_dec->fmt_out.audio.i_original_channels = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
124
    if( p_dec->fmt_in.i_extra > 0 )
125 126
    {
        /* We have a decoder config so init the handle */
Gildas Bazin's avatar
 
Gildas Bazin committed
127 128
        unsigned long i_rate;
        unsigned char i_channels;
129

Gildas Bazin's avatar
 
Gildas Bazin committed
130 131
        if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
                          p_dec->fmt_in.i_extra,
132 133 134 135 136
                          &i_rate, &i_channels ) < 0 )
        {
            return VLC_EGENERIC;
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
137 138 139
        p_dec->fmt_out.audio.i_rate = i_rate;
        p_dec->fmt_out.audio.i_channels = i_channels;
        aout_DateInit( &p_sys->date, i_rate );
140 141 142 143
    }
    else
    {
        /* Will be initalised from first frame */
Gildas Bazin's avatar
 
Gildas Bazin committed
144 145
        p_dec->fmt_out.audio.i_rate = 0;
        p_dec->fmt_out.audio.i_channels = 0;
146 147
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
148
    /* Set the faad config */
149 150 151 152 153
    cfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
    cfg->outputFormat = FAAD_FMT_FLOAT;
    faacDecSetConfiguration( p_sys->hfaad, cfg );

    /* buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
154 155
    p_sys->i_buffer = p_sys->i_buffer_size = 0;
    p_sys->p_buffer = 0;
156 157 158 159 160

    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
161
 * DecodeBlock:
162
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
163
static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
164 165
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
166
    block_t *p_block;
167

Gildas Bazin's avatar
 
Gildas Bazin committed
168 169 170
    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
171

172 173 174 175 176 177
    if( p_block->b_discontinuity )
    {
        block_Release( p_block );
        return NULL;
    }

178 179 180
    /* Append the block to the temporary buffer */
    if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
181
        p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
182 183 184
        p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
185 186 187 188 189 190 191 192 193
    if( p_block->i_buffer )
    {
        memcpy( &p_sys->p_buffer[p_sys->i_buffer],
                p_block->p_buffer, p_block->i_buffer );
        p_sys->i_buffer += p_block->i_buffer;
        p_block->i_buffer = 0;
    }

    if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer )
194
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
195 196
        unsigned long i_rate;
        unsigned char i_channels;
197 198 199 200 201 202

        /* Init faad with the first frame */
        if( faacDecInit( p_sys->hfaad,
                         p_sys->p_buffer, p_sys->i_buffer,
                         &i_rate, &i_channels ) < 0 )
        {
203
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
204
            return NULL;
205
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

        p_dec->fmt_out.audio.i_rate = i_rate;
        p_dec->fmt_out.audio.i_channels = i_channels;
        aout_DateInit( &p_sys->date, i_rate );
    }

    if( p_block->i_pts != 0 && p_block->i_pts != aout_DateGet( &p_sys->date ) )
    {
        aout_DateSet( &p_sys->date, p_block->i_pts );
    }
    else if( !aout_DateGet( &p_sys->date ) )
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
        p_sys->i_buffer = 0;
        return NULL;
222 223 224
    }

    /* Decode all data */
Gildas Bazin's avatar
 
Gildas Bazin committed
225
    if( p_sys->i_buffer )
226 227 228
    {
        void *samples;
        faacDecFrameInfo frame;
Gildas Bazin's avatar
 
Gildas Bazin committed
229
        aout_buffer_t *p_out;
Gildas Bazin's avatar
 
Gildas Bazin committed
230
        int i, j;
231 232

        samples = faacDecDecode( p_sys->hfaad, &frame,
Gildas Bazin's avatar
 
Gildas Bazin committed
233
                                 p_sys->p_buffer, p_sys->i_buffer );
234 235 236 237

        if( frame.error > 0 )
        {
            msg_Warn( p_dec, "%s", faacDecGetErrorMessage( frame.error ) );
Gildas Bazin's avatar
 
Gildas Bazin committed
238 239

            /* Flush the buffer */
240
            p_sys->i_buffer = 0;
241
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
242
            return NULL;
243
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
244

Gildas Bazin's avatar
 
Gildas Bazin committed
245
        if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
246
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
247
            msg_Warn( p_dec, "invalid channels count: %i", frame.channels );
Gildas Bazin's avatar
 
Gildas Bazin committed
248 249

            /* Flush the buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
250 251 252 253 254 255
            p_sys->i_buffer -= frame.bytesconsumed;
            if( p_sys->i_buffer > 0 )
            {
                memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed],
                         p_sys->i_buffer );
            }
256
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
257
            return NULL;
258
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
259

260 261 262
        if( frame.samples <= 0 )
        {
            msg_Warn( p_dec, "decoded zero samples" );
Gildas Bazin's avatar
 
Gildas Bazin committed
263 264

            /* Flush the buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
265 266 267 268 269 270
            p_sys->i_buffer -= frame.bytesconsumed;
            if( p_sys->i_buffer > 0 )
            {
                memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed],
                         p_sys->i_buffer );
            }
271
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
272
            return NULL;
273 274
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
275 276
        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
277
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
278 279
            aout_DateInit( &p_sys->date, frame.samplerate );
            aout_DateSet( &p_sys->date, p_block->i_pts );
280
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
281
        p_block->i_pts = 0;  /* PTS is valid only once */
282

Gildas Bazin's avatar
 
Gildas Bazin committed
283 284
        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
285

Gildas Bazin's avatar
 
Gildas Bazin committed
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305

        /* Convert frame.channel_position to our own channel values */
        for( i = 0; i < frame.channels; i++ )
        {
            /* Find the channel code */
            for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ )
            {
                if( frame.channel_position[i] == pi_channels_in[j] )
                {
                    p_sys->pi_channel_positions[i] = pi_channels_out[j];
                    p_dec->fmt_out.audio.i_physical_channels |=
                        pi_channels_out[j];
                    break;
                }
            }
        }
        p_dec->fmt_out.audio.i_original_channels =
            p_dec->fmt_out.audio.i_physical_channels;

        p_out = p_dec->pf_aout_buffer_new(p_dec, frame.samples/frame.channels);
Gildas Bazin's avatar
 
Gildas Bazin committed
306
        if( p_out == NULL )
307
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
308
            p_sys->i_buffer = 0;
309
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
310
            return NULL;
311 312
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
313 314 315 316
        p_out->start_date = aout_DateGet( &p_sys->date );
        p_out->end_date = aout_DateIncrement( &p_sys->date,
                                              frame.samples / frame.channels );

Gildas Bazin's avatar
 
Gildas Bazin committed
317 318 319
        DoReordering( p_dec, (uint32_t *)p_out->p_buffer, samples,
                      frame.samples / frame.channels, frame.channels,
                      p_sys->pi_channel_positions );
320

Gildas Bazin's avatar
 
Gildas Bazin committed
321 322
        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
323
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
324 325
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
326 327
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
328
        return p_out;
329 330
    }

331
    block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
332
    return NULL;
333 334 335
}

/*****************************************************************************
336
 * Close:
337
 *****************************************************************************/
338
static void Close( vlc_object_t *p_this )
339
{
Gildas Bazin's avatar
 
Gildas Bazin committed
340
    decoder_t *p_dec = (decoder_t *)p_this;
341 342 343 344 345
    decoder_sys_t *p_sys = p_dec->p_sys;

    faacDecClose( p_sys->hfaad );
    free( p_sys );
}
Gildas Bazin's avatar
 
Gildas Bazin committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380

/*****************************************************************************
 * DoReordering: do some channel re-ordering (the ac3 channel order is
 *   different from the aac one).
 *****************************************************************************/
static void DoReordering( decoder_t *p_dec,
                          uint32_t *p_out, uint32_t *p_in, int i_samples,
                          int i_nb_channels, uint32_t *pi_chan_positions )
{
    int pi_chan_table[MAX_CHANNEL_POSITIONS];
    int i, j, k;

    /* Find the channels mapping */
    for( i = 0, j = 0; i < MAX_CHANNEL_POSITIONS; i++ )
    {
        for( k = 0; k < i_nb_channels; k++ )
        {
            if( pi_channels_ordered[i] == pi_chan_positions[k] )
            {
                pi_chan_table[k] = j++;
                break;
            }
        }
    }

    /* Do the actual reordering */
    for( i = 0; i < i_samples; i++ )
    {
        for( j = 0; j < i_nb_channels; j++ )
        {
            p_out[i * i_nb_channels + pi_chan_table[j]] =
                p_in[i * i_nb_channels + j];
        }
    }
}