faad.c 18.7 KB
Newer Older
1
/*****************************************************************************
Pere Orga's avatar
Pere Orga committed
2
 * faad.c: AAC decoder using libfaad2
3
 *****************************************************************************
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
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24
 *****************************************************************************/

25 26 27 28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
#include <vlc_common.h>
30
#include <vlc_plugin.h>
31
#include <vlc_input.h>
zorglub's avatar
zorglub committed
32
#include <vlc_codec.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
33
#include <vlc_cpu.h>
34 35 36 37 38 39 40

#include <faad.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open( vlc_object_t * );
41
static void Close( vlc_object_t * );
42

43 44 45 46 47 48 49
vlc_module_begin ()
    set_description( N_("AAC audio decoder (using libfaad2)") )
    set_capability( "decoder", 100 )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACODEC )
    set_callbacks( Open, Close )
vlc_module_end ()
50 51 52 53

/****************************************************************************
 * Local prototypes
 ****************************************************************************/
54
static block_t *DecodeBlock( decoder_t *, block_t ** );
55
static void DoReordering( uint32_t *, uint32_t *, int, int, uint32_t * );
gbazin's avatar
 
gbazin committed
56 57

#define MAX_CHANNEL_POSITIONS 9
58 59 60 61 62 63 64

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

    /* samples */
65
    date_t date;
66 67

    /* temporary buffer */
gbazin's avatar
 
gbazin committed
68 69
    uint8_t *p_buffer;
    int     i_buffer;
70
    size_t  i_buffer_size;
71

gbazin's avatar
 
gbazin committed
72 73
    /* Channel positions of the current stream (for re-ordering) */
    uint32_t pi_channel_positions[MAX_CHANNEL_POSITIONS];
74

75
    bool b_sbr, b_ps;
76 77
};

gbazin's avatar
 
gbazin committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
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
    };
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
static const uint32_t pi_channels_guessed[MAX_CHANNEL_POSITIONS] =
    { 0, AOUT_CHAN_CENTER, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
      AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE,
      AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
          | AOUT_CHAN_REARRIGHT,
      AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
          | AOUT_CHAN_REARRIGHT | AOUT_CHAN_CENTER,
      AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
          | AOUT_CHAN_REARRIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_LFE,
      AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_MIDDLELEFT
          | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
          | AOUT_CHAN_CENTER,
      AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_MIDDLELEFT
          | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
          | AOUT_CHAN_CENTER | AOUT_CHAN_LFE
    };
gbazin's avatar
 
gbazin committed
110

111
/*****************************************************************************
gbazin's avatar
 
gbazin committed
112
 * OpenDecoder: probe the decoder and return score
113
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
114
static int Open( vlc_object_t *p_this )
115
{
gbazin's avatar
 
gbazin committed
116
    decoder_t *p_dec = (decoder_t*)p_this;
117 118 119
    decoder_sys_t *p_sys = p_dec->p_sys;
    faacDecConfiguration *cfg;

120
    if( p_dec->fmt_in.i_codec != VLC_CODEC_MP4A )
121
    {
gbazin's avatar
 
gbazin committed
122 123 124 125
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
126
    if( ( p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) ) ) == NULL )
127
        return VLC_ENOMEM;
128 129 130 131

    /* Open a faad context */
    if( ( p_sys->hfaad = faacDecOpen() ) == NULL )
    {
bigben's avatar
bigben committed
132
        msg_Err( p_dec, "cannot initialize faad" );
ivoire's avatar
ivoire committed
133
        free( p_sys );
134 135 136
        return VLC_EGENERIC;
    }

gbazin's avatar
 
gbazin committed
137
    /* Misc init */
138
    date_Set( &p_sys->date, 0 );
gbazin's avatar
 
gbazin committed
139
    p_dec->fmt_out.i_cat = AUDIO_ES;
140

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
141
    if (HAVE_FPU)
142
        p_dec->fmt_out.i_codec = VLC_CODEC_FL32;
143
    else
144
        p_dec->fmt_out.i_codec = VLC_CODEC_S16N;
gbazin's avatar
 
gbazin committed
145 146
    p_dec->pf_decode_audio = DecodeBlock;

gbazin's avatar
 
gbazin committed
147 148 149
    p_dec->fmt_out.audio.i_physical_channels =
        p_dec->fmt_out.audio.i_original_channels = 0;

gbazin's avatar
 
gbazin committed
150
    if( p_dec->fmt_in.i_extra > 0 )
151 152
    {
        /* We have a decoder config so init the handle */
gbazin's avatar
 
gbazin committed
153 154
        unsigned long i_rate;
        unsigned char i_channels;
155

gbazin's avatar
 
gbazin committed
156 157
        if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
                          p_dec->fmt_in.i_extra,
158 159
                          &i_rate, &i_channels ) < 0 )
        {
160
            msg_Err( p_dec, "Failed to initialize faad using extra data" );
ivoire's avatar
ivoire committed
161 162
            faacDecClose( p_sys->hfaad );
            free( p_sys );
163 164 165
            return VLC_EGENERIC;
        }

gbazin's avatar
 
gbazin committed
166 167
        p_dec->fmt_out.audio.i_rate = i_rate;
        p_dec->fmt_out.audio.i_channels = i_channels;
168 169 170
        p_dec->fmt_out.audio.i_physical_channels
            = p_dec->fmt_out.audio.i_original_channels
            = pi_channels_guessed[i_channels];
171
        date_Init( &p_sys->date, i_rate, 1 );
172 173 174 175
    }
    else
    {
        /* Will be initalised from first frame */
gbazin's avatar
 
gbazin committed
176 177
        p_dec->fmt_out.audio.i_rate = 0;
        p_dec->fmt_out.audio.i_channels = 0;
178 179
    }

gbazin's avatar
 
gbazin committed
180
    /* Set the faad config */
181
    cfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
182
    if (HAVE_FPU)
183 184
        cfg->outputFormat = FAAD_FMT_FLOAT;
    else
185
        cfg->outputFormat = FAAD_FMT_16BIT;
186 187 188
    faacDecSetConfiguration( p_sys->hfaad, cfg );

    /* buffer */
gbazin's avatar
 
gbazin committed
189
    p_sys->i_buffer = p_sys->i_buffer_size = 0;
190
    p_sys->p_buffer = NULL;
191

192
    /* Faad2 can't deal with truncated data (eg. from MPEG TS) */
193
    p_dec->b_need_packetized = true;
194

195
    p_sys->b_sbr = p_sys->b_ps = false;
196 197 198 199
    return VLC_SUCCESS;
}

/*****************************************************************************
gbazin's avatar
 
gbazin committed
200
 * DecodeBlock:
201
 *****************************************************************************/
202
static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
203 204
{
    decoder_sys_t *p_sys = p_dec->p_sys;
205
    block_t *p_block;
206

207 208 209
    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
210

Laurent Aimar's avatar
Laurent Aimar committed
211
    if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
212 213 214 215 216
    {
        block_Release( p_block );
        return NULL;
    }

217 218 219 220 221 222 223 224 225 226 227
    /* Remove ADTS header if we have decoder specific config */
    if( p_dec->fmt_in.i_extra && p_block->i_buffer > 7 )
    {
        if( p_block->p_buffer[0] == 0xff &&
            ( p_block->p_buffer[1] & 0xf0 ) == 0xf0 ) /* syncword */
        {   /* ADTS header present */
            size_t i_header_size; /* 7 bytes (+ 2 bytes for crc) */
            i_header_size = 7 + ( ( p_block->p_buffer[1] & 0x01 ) ? 0 : 2 );
            /* FIXME: multiple blocks per frame */
            if( p_block->i_buffer > i_header_size )
            {
228
                p_block->p_buffer += i_header_size;
229 230 231 232 233
                p_block->i_buffer -= i_header_size;
            }
        }
    }

234 235 236
    /* Append the block to the temporary buffer */
    if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer )
    {
237 238 239 240 241 242 243 244 245 246 247
        size_t  i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
        uint8_t *p_buffer     = realloc( p_sys->p_buffer, i_buffer_size );
        if( p_buffer )
        {
            p_sys->i_buffer_size = i_buffer_size;
            p_sys->p_buffer      = p_buffer;
        }
        else
        {
            p_block->i_buffer = 0;
        }
248 249
    }

250
    if( p_block->i_buffer > 0 )
gbazin's avatar
 
gbazin committed
251
    {
Rafaël Carré's avatar
Rafaël Carré committed
252
        memcpy( &p_sys->p_buffer[p_sys->i_buffer],
253
                     p_block->p_buffer, p_block->i_buffer );
gbazin's avatar
 
gbazin committed
254 255 256 257
        p_sys->i_buffer += p_block->i_buffer;
        p_block->i_buffer = 0;
    }

258 259 260 261 262 263 264 265 266 267 268 269
    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;
270 271 272 273
            p_dec->fmt_out.audio.i_physical_channels
                = p_dec->fmt_out.audio.i_original_channels
                = pi_channels_guessed[i_channels];

274
            date_Init( &p_sys->date, i_rate, 1 );
275 276 277
        }
    }

gbazin's avatar
 
gbazin committed
278
    if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer )
279
    {
gbazin's avatar
 
gbazin committed
280 281
        unsigned long i_rate;
        unsigned char i_channels;
282 283 284 285 286 287

        /* Init faad with the first frame */
        if( faacDecInit( p_sys->hfaad,
                         p_sys->p_buffer, p_sys->i_buffer,
                         &i_rate, &i_channels ) < 0 )
        {
288
            block_Release( p_block );
gbazin's avatar
 
gbazin committed
289
            return NULL;
290
        }
gbazin's avatar
 
gbazin committed
291 292 293

        p_dec->fmt_out.audio.i_rate = i_rate;
        p_dec->fmt_out.audio.i_channels = i_channels;
294 295 296
        p_dec->fmt_out.audio.i_physical_channels
            = p_dec->fmt_out.audio.i_original_channels
            = pi_channels_guessed[i_channels];
297
        date_Init( &p_sys->date, i_rate, 1 );
gbazin's avatar
 
gbazin committed
298 299
    }

300
    if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->date ) )
gbazin's avatar
 
gbazin committed
301
    {
302
        date_Set( &p_sys->date, p_block->i_pts );
gbazin's avatar
 
gbazin committed
303
    }
304
    else if( !date_Get( &p_sys->date ) )
gbazin's avatar
 
gbazin committed
305 306 307 308 309
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
        p_sys->i_buffer = 0;
        return NULL;
310 311 312
    }

    /* Decode all data */
gbazin's avatar
 
gbazin committed
313
    if( p_sys->i_buffer )
314 315 316
    {
        void *samples;
        faacDecFrameInfo frame;
317
        block_t *p_out;
318 319

        samples = faacDecDecode( p_sys->hfaad, &frame,
gbazin's avatar
 
gbazin committed
320
                                 p_sys->p_buffer, p_sys->i_buffer );
321 322 323 324

        if( frame.error > 0 )
        {
            msg_Warn( p_dec, "%s", faacDecGetErrorMessage( frame.error ) );
gbazin's avatar
 
gbazin committed
325

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
            if( frame.error == 21 )
            {
                /*
                 * Once an "Unexpected channel configuration change" error
                 * occurs, it will occurs afterwards, and we got no sound.
                 * Reinitialization of the decoder is required.
                 */
                unsigned long i_rate;
                unsigned char i_channels;
                faacDecHandle *hfaad;
                faacDecConfiguration *cfg,*oldcfg;

                oldcfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
                hfaad = faacDecOpen();
                cfg = faacDecGetCurrentConfiguration( hfaad );
                if( oldcfg->defSampleRate )
                    cfg->defSampleRate = oldcfg->defSampleRate;
                cfg->defObjectType = oldcfg->defObjectType;
                cfg->outputFormat = oldcfg->outputFormat;
                faacDecSetConfiguration( hfaad, cfg );

                if( faacDecInit( hfaad, p_sys->p_buffer, p_sys->i_buffer,
                                &i_rate,&i_channels ) < 0 )
                {
                    /* reinitialization failed */
                    faacDecClose( hfaad );
                    faacDecSetConfiguration( p_sys->hfaad, oldcfg );
                }
                else
                {
                    faacDecClose( p_sys->hfaad );
                    p_sys->hfaad = hfaad;
                    p_dec->fmt_out.audio.i_rate = i_rate;
                    p_dec->fmt_out.audio.i_channels = i_channels;
                    p_dec->fmt_out.audio.i_physical_channels
                        = p_dec->fmt_out.audio.i_original_channels
                        = pi_channels_guessed[i_channels];
                    date_Init( &p_sys->date, i_rate, 1 );
                }
            }

gbazin's avatar
 
gbazin committed
367
            /* Flush the buffer */
368
            p_sys->i_buffer = 0;
369
            block_Release( p_block );
gbazin's avatar
 
gbazin committed
370
            return NULL;
371
        }
gbazin's avatar
 
gbazin committed
372

gbazin's avatar
 
gbazin committed
373
        if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
374
        {
gbazin's avatar
 
gbazin committed
375
            msg_Warn( p_dec, "invalid channels count: %i", frame.channels );
gbazin's avatar
 
gbazin committed
376 377

            /* Flush the buffer */
gbazin's avatar
 
gbazin committed
378 379 380 381 382 383
            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 );
            }
384
            block_Release( p_block );
gbazin's avatar
 
gbazin committed
385
            return NULL;
386
        }
gbazin's avatar
 
gbazin committed
387

388 389
        if( frame.samples <= 0 )
        {
bigben's avatar
bigben committed
390
            msg_Warn( p_dec, "decoded zero sample" );
gbazin's avatar
 
gbazin committed
391 392

            /* Flush the buffer */
gbazin's avatar
 
gbazin committed
393 394 395 396 397 398
            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 );
            }
399
            block_Release( p_block );
gbazin's avatar
 
gbazin committed
400
            return NULL;
401 402
        }

gbazin's avatar
 
gbazin committed
403 404
        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
405
        {
406 407
            date_Init( &p_sys->date, frame.samplerate, 1 );
            date_Set( &p_sys->date, p_block->i_pts );
408
        }
409
        p_block->i_pts = VLC_TS_INVALID;  /* PTS is valid only once */
410

gbazin's avatar
 
gbazin committed
411 412
        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
413

414
        /* Adjust stream info when dealing with SBR/PS */
415 416
        bool b_sbr = (frame.sbr == 1) || (frame.sbr == 2);
        if( p_sys->b_sbr != b_sbr || p_sys->b_ps != frame.ps )
417
        {
418 419
            const char *psz_ext = (b_sbr && frame.ps) ? "SBR+PS" :
                                    b_sbr ? "SBR" : "PS";
420

421 422 423
            msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)",
                    psz_ext, frame.channels, frame.samplerate );

424 425 426 427 428
            if( !p_dec->p_description )
                p_dec->p_description = vlc_meta_New();
            if( p_dec->p_description )
                vlc_meta_AddExtra( p_dec->p_description, _("AAC extension"), psz_ext );

429 430
            p_sys->b_sbr = b_sbr;
            p_sys->b_ps = frame.ps;
431
        }
gbazin's avatar
 
gbazin committed
432 433

        /* Convert frame.channel_position to our own channel values */
434
        p_dec->fmt_out.audio.i_physical_channels = 0;
435
        const uint32_t nbChannels = frame.channels;
436 437
        unsigned j;
        for( unsigned i = 0; i < nbChannels; i++ )
gbazin's avatar
 
gbazin committed
438 439 440 441 442 443 444
        {
            /* Find the channel code */
            for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ )
            {
                if( frame.channel_position[i] == pi_channels_in[j] )
                    break;
            }
445
            if( j >= MAX_CHANNEL_POSITIONS )
446
            {
hartman's avatar
hartman committed
447
                msg_Warn( p_dec, "unknown channel ordering" );
448 449
                /* Invent something */
                j = i;
450
            }
451 452 453 454 455 456
            /* */
            p_sys->pi_channel_positions[i] = pi_channels_out[j];
            if( p_dec->fmt_out.audio.i_physical_channels & pi_channels_out[j] )
                frame.channels--; /* We loose a duplicated channel */
            else
                p_dec->fmt_out.audio.i_physical_channels |= pi_channels_out[j];
gbazin's avatar
 
gbazin committed
457
        }
458 459 460 461 462 463 464 465 466 467 468 469 470
        if ( nbChannels != frame.channels )
        {
            p_dec->fmt_out.audio.i_physical_channels
                = p_dec->fmt_out.audio.i_original_channels
                = pi_channels_guessed[nbChannels];
        }
        else
        {
            p_dec->fmt_out.audio.i_original_channels =
                p_dec->fmt_out.audio.i_physical_channels;
        }
        p_dec->fmt_out.audio.i_channels = nbChannels;
        p_out = decoder_NewAudioBuffer( p_dec, frame.samples / nbChannels );
gbazin's avatar
 
gbazin committed
471
        if( p_out == NULL )
472
        {
gbazin's avatar
 
gbazin committed
473
            p_sys->i_buffer = 0;
474
            block_Release( p_block );
gbazin's avatar
 
gbazin committed
475
            return NULL;
476 477
        }

478
        p_out->i_pts = date_Get( &p_sys->date );
479
        p_out->i_length = date_Increment( &p_sys->date,
480
                                          frame.samples / nbChannels )
481
                          - p_out->i_pts;
gbazin's avatar
 
gbazin committed
482

483
        DoReordering( (uint32_t *)p_out->p_buffer, samples,
484
                      frame.samples / nbChannels, nbChannels,
gbazin's avatar
 
gbazin committed
485
                      p_sys->pi_channel_positions );
486

gbazin's avatar
 
gbazin committed
487 488
        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
489
        {
gbazin's avatar
 
gbazin committed
490 491
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
492 493
        }

gbazin's avatar
 
gbazin committed
494
        return p_out;
495 496
    }

497
    block_Release( p_block );
gbazin's avatar
 
gbazin committed
498
    return NULL;
499 500 501
}

/*****************************************************************************
502
 * Close:
503
 *****************************************************************************/
504
static void Close( vlc_object_t *p_this )
505
{
gbazin's avatar
 
gbazin committed
506
    decoder_t *p_dec = (decoder_t *)p_this;
507 508 509
    decoder_sys_t *p_sys = p_dec->p_sys;

    faacDecClose( p_sys->hfaad );
ivoire's avatar
ivoire committed
510
    free( p_sys->p_buffer );
511 512
    free( p_sys );
}
gbazin's avatar
 
gbazin committed
513 514 515 516 517

/*****************************************************************************
 * DoReordering: do some channel re-ordering (the ac3 channel order is
 *   different from the aac one).
 *****************************************************************************/
518
static void DoReordering( uint32_t *p_out, uint32_t *p_in, int i_samples,
gbazin's avatar
 
gbazin committed
519 520
                          int i_nb_channels, uint32_t *pi_chan_positions )
{
521
    int pi_chan_table[MAX_CHANNEL_POSITIONS] = {0};
gbazin's avatar
 
gbazin committed
522 523 524
    int i, j, k;

    /* Find the channels mapping */
525
    for( i = 0, j = 0; i < MAX_CHANNEL_POSITIONS; i++ )
gbazin's avatar
 
gbazin committed
526
    {
527
        for( k = 0; k < i_nb_channels; k++ )
gbazin's avatar
 
gbazin committed
528 529 530 531 532 533 534 535 536 537
        {
            if( pi_channels_ordered[i] == pi_chan_positions[k] )
            {
                pi_chan_table[k] = j++;
                break;
            }
        }
    }

    /* Do the actual reordering */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
538
    if( HAVE_FPU )
539 540 541 542 543 544 545 546 547
        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];
gbazin's avatar
 
gbazin committed
548
}
549