faad.c 13.5 KB
Newer Older
1 2 3
/*****************************************************************************
 * decoder.c: AAC decoder using libfaad2
 *****************************************************************************
4
 * Copyright (C) 2001, 2003 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24
 *****************************************************************************/

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 );
Clément Stenac's avatar
Clément Stenac committed
40 41
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACODEC );
42
    set_callbacks( Open, Close );
43 44 45 46 47
vlc_module_end();

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

#define MAX_CHANNEL_POSITIONS 9
53 54 55 56 57 58 59

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

    /* samples */
Gildas Bazin's avatar
 
Gildas Bazin committed
60
    audio_date_t date;
61 62

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
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
    };

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

Gildas Bazin's avatar
 
Gildas Bazin committed
97
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','4','a') )
98
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
99 100 101 102 103 104 105 106 107
        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;
108 109 110 111 112
    }

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

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

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

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

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

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

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

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

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

166 167 168
    /* Faad2 can't deal with truncated data (eg. from MPEG TS) */
    p_dec->b_need_packetized = VLC_TRUE;

169 170 171 172
    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
173
 * DecodeBlock:
174
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
175
static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
176 177
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
178
    block_t *p_block;
179

Gildas Bazin's avatar
 
Gildas Bazin committed
180 181 182
    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
183

Laurent Aimar's avatar
Laurent Aimar committed
184
    if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
185 186 187 188 189
    {
        block_Release( p_block );
        return NULL;
    }

190 191 192
    /* 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
193
        p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
194 195 196
        p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
197 198 199 200 201 202 203 204
    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;
    }

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    if( p_dec->fmt_out.audio.i_rate == 0 && p_dec->fmt_in.i_extra > 0 )
    {
        /* We have a decoder config so init the handle */
        unsigned long i_rate;
        unsigned char i_channels;

        if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
                          p_dec->fmt_in.i_extra,
                          &i_rate, &i_channels ) >= 0 )
        {
            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 );
        }
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
221
    if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer )
222
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
223 224
        unsigned long i_rate;
        unsigned char i_channels;
225 226 227 228 229 230

        /* Init faad with the first frame */
        if( faacDecInit( p_sys->hfaad,
                         p_sys->p_buffer, p_sys->i_buffer,
                         &i_rate, &i_channels ) < 0 )
        {
231
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
232
            return NULL;
233
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

        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;
250 251 252
    }

    /* Decode all data */
Gildas Bazin's avatar
 
Gildas Bazin committed
253
    if( p_sys->i_buffer )
254 255 256
    {
        void *samples;
        faacDecFrameInfo frame;
Gildas Bazin's avatar
 
Gildas Bazin committed
257
        aout_buffer_t *p_out;
Gildas Bazin's avatar
 
Gildas Bazin committed
258
        int i, j;
259 260

        samples = faacDecDecode( p_sys->hfaad, &frame,
Gildas Bazin's avatar
 
Gildas Bazin committed
261
                                 p_sys->p_buffer, p_sys->i_buffer );
262 263 264 265

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

            /* Flush the buffer */
268
            p_sys->i_buffer = 0;
269
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
270
            return NULL;
271
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
272

Gildas Bazin's avatar
 
Gildas Bazin committed
273
        if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
274
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
275
            msg_Warn( p_dec, "invalid channels count: %i", frame.channels );
Gildas Bazin's avatar
 
Gildas Bazin committed
276 277

            /* Flush the buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
278 279 280 281 282 283
            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 );
            }
284
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
285
            return NULL;
286
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
287

288 289
        if( frame.samples <= 0 )
        {
Benjamin Pracht's avatar
Benjamin Pracht committed
290
            msg_Warn( p_dec, "decoded zero sample" );
Gildas Bazin's avatar
 
Gildas Bazin committed
291 292

            /* Flush the buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
293 294 295 296 297 298
            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 );
            }
299
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
300
            return NULL;
301 302
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
303 304
        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
305
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
306 307
            aout_DateInit( &p_sys->date, frame.samplerate );
            aout_DateSet( &p_sys->date, p_block->i_pts );
308
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
309
        p_block->i_pts = 0;  /* PTS is valid only once */
310

Gildas Bazin's avatar
 
Gildas Bazin committed
311 312
        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
313

Gildas Bazin's avatar
 
Gildas Bazin committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

        /* 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;
                }
            }
329 330 331

            if( j == MAX_CHANNEL_POSITIONS )
            {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
332
                msg_Warn( p_dec, "unknown channel ordering" );
333 334 335
                block_Release( p_block );
                return NULL;
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
336 337 338 339 340
        }
        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
341
        if( p_out == NULL )
342
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
343
            p_sys->i_buffer = 0;
344
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
345
            return NULL;
346 347
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
348 349 350 351
        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
352 353 354
        DoReordering( p_dec, (uint32_t *)p_out->p_buffer, samples,
                      frame.samples / frame.channels, frame.channels,
                      p_sys->pi_channel_positions );
355

Gildas Bazin's avatar
 
Gildas Bazin committed
356 357
        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
358
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
359 360
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
361 362
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
363
        return p_out;
364 365
    }

366
    block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
367
    return NULL;
368 369 370
}

/*****************************************************************************
371
 * Close:
372
 *****************************************************************************/
373
static void Close( vlc_object_t *p_this )
374
{
Gildas Bazin's avatar
 
Gildas Bazin committed
375
    decoder_t *p_dec = (decoder_t *)p_this;
376 377 378 379 380
    decoder_sys_t *p_sys = p_dec->p_sys;

    faacDecClose( p_sys->hfaad );
    free( p_sys );
}
Gildas Bazin's avatar
 
Gildas Bazin committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406

/*****************************************************************************
 * 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 */
407
    if( p_dec->p_libvlc_global->i_cpu & CPU_CAPABILITY_FPU )
408 409 410 411 412 413 414 415 416
        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
417
}