faad.c 12.5 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * decoder.c: AAC decoder using libfaad2
 *****************************************************************************
 * Copyright (C) 2001, 2003 VideoLAN
5
 * $Id: faad.c,v 1.14 2004/02/25 17:48:52 fenrir 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
    }

    /* Open a faad context */
    if( ( p_sys->hfaad = faacDecOpen() ) == NULL )
    {
Benjamin Pracht's avatar
Benjamin Pracht committed
111
        msg_Err( p_dec, "cannot initialize faad" );
112 113 114
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
115 116 117
    /* Misc init */
    aout_DateSet( &p_sys->date, 0 );
    p_dec->fmt_out.i_cat = AUDIO_ES;
118

119
    if (p_this->p_libvlc->i_cpu & CPU_CAPABILITY_FPU)
120 121
        p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
    else
122
        p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE;
Gildas Bazin's avatar
 
Gildas Bazin committed
123 124
    p_dec->pf_decode_audio = DecodeBlock;

Gildas Bazin's avatar
 
Gildas Bazin committed
125 126 127
    p_dec->fmt_out.audio.i_physical_channels =
        p_dec->fmt_out.audio.i_original_channels = 0;

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
141 142 143
        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 );
144 145 146 147
    }
    else
    {
        /* Will be initalised from first frame */
Gildas Bazin's avatar
 
Gildas Bazin committed
148 149
        p_dec->fmt_out.audio.i_rate = 0;
        p_dec->fmt_out.audio.i_channels = 0;
150 151
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
152
    /* Set the faad config */
153
    cfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
154
    if (p_this->p_libvlc->i_cpu & CPU_CAPABILITY_FPU)
155 156
        cfg->outputFormat = FAAD_FMT_FLOAT;
    else
157
        cfg->outputFormat = FAAD_FMT_16BIT;
158 159 160
    faacDecSetConfiguration( p_sys->hfaad, cfg );

    /* buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
161 162
    p_sys->i_buffer = p_sys->i_buffer_size = 0;
    p_sys->p_buffer = 0;
163 164 165 166 167

    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
168
 * DecodeBlock:
169
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
170
static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
171 172
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
173
    block_t *p_block;
174

Gildas Bazin's avatar
 
Gildas Bazin committed
175 176 177
    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
178

179
    if( p_block->i_flags&BLOCK_FLAG_DISCONTINUITY )
180 181 182 183 184
    {
        block_Release( p_block );
        return NULL;
    }

185 186 187
    /* 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
188
        p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
189 190 191
        p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
192 193 194 195 196 197 198 199 200
    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 )
201
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
202 203
        unsigned long i_rate;
        unsigned char i_channels;
204 205 206 207 208 209

        /* Init faad with the first frame */
        if( faacDecInit( p_sys->hfaad,
                         p_sys->p_buffer, p_sys->i_buffer,
                         &i_rate, &i_channels ) < 0 )
        {
210
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
211
            return NULL;
212
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

        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;
229 230 231
    }

    /* Decode all data */
Gildas Bazin's avatar
 
Gildas Bazin committed
232
    if( p_sys->i_buffer )
233 234 235
    {
        void *samples;
        faacDecFrameInfo frame;
Gildas Bazin's avatar
 
Gildas Bazin committed
236
        aout_buffer_t *p_out;
Gildas Bazin's avatar
 
Gildas Bazin committed
237
        int i, j;
238 239

        samples = faacDecDecode( p_sys->hfaad, &frame,
Gildas Bazin's avatar
 
Gildas Bazin committed
240
                                 p_sys->p_buffer, p_sys->i_buffer );
241 242 243 244

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

            /* Flush the buffer */
247
            p_sys->i_buffer = 0;
248
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
249
            return NULL;
250
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
251

Gildas Bazin's avatar
 
Gildas Bazin committed
252
        if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
253
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
254
            msg_Warn( p_dec, "invalid channels count: %i", frame.channels );
Gildas Bazin's avatar
 
Gildas Bazin committed
255 256

            /* Flush the buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
257 258 259 260 261 262
            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 );
            }
263
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
264
            return NULL;
265
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
266

267 268
        if( frame.samples <= 0 )
        {
Benjamin Pracht's avatar
Benjamin Pracht committed
269
            msg_Warn( p_dec, "decoded zero sample" );
Gildas Bazin's avatar
 
Gildas Bazin committed
270 271

            /* Flush the buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
272 273 274 275 276 277
            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 );
            }
278
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
279
            return NULL;
280 281
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
282 283
        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
284
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
285 286
            aout_DateInit( &p_sys->date, frame.samplerate );
            aout_DateSet( &p_sys->date, p_block->i_pts );
287
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
288
        p_block->i_pts = 0;  /* PTS is valid only once */
289

Gildas Bazin's avatar
 
Gildas Bazin committed
290 291
        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
292

Gildas Bazin's avatar
 
Gildas Bazin committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

        /* 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
313
        if( p_out == NULL )
314
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
315
            p_sys->i_buffer = 0;
316
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
317
            return NULL;
318 319
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
320 321 322 323
        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
324 325 326
        DoReordering( p_dec, (uint32_t *)p_out->p_buffer, samples,
                      frame.samples / frame.channels, frame.channels,
                      p_sys->pi_channel_positions );
327

Gildas Bazin's avatar
 
Gildas Bazin committed
328 329
        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
330
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
331 332
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
333 334
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
335
        return p_out;
336 337
    }

338
    block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
339
    return NULL;
340 341 342
}

/*****************************************************************************
343
 * Close:
344
 *****************************************************************************/
345
static void Close( vlc_object_t *p_this )
346
{
Gildas Bazin's avatar
 
Gildas Bazin committed
347
    decoder_t *p_dec = (decoder_t *)p_this;
348 349 350 351 352
    decoder_sys_t *p_sys = p_dec->p_sys;

    faacDecClose( p_sys->hfaad );
    free( p_sys );
}
Gildas Bazin's avatar
 
Gildas Bazin committed
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

/*****************************************************************************
 * 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 */
379 380 381 382 383 384 385 386 387 388
    if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_FPU )
        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];
    else
        for( i = 0; i < i_samples; i++ )
            for( j = 0; j < i_nb_channels; j++ )
                ((uint16_t *)p_out)[i * i_nb_channels + pi_chan_table[j]] =
                    ((uint16_t *)p_in)[i * i_nb_channels + j];
Gildas Bazin's avatar
 
Gildas Bazin committed
389
}