faad.c 19.1 KB
Newer Older
1
/*****************************************************************************
Pere Orga's avatar
Pere Orga committed
2
 * faad.c: AAC decoder using libfaad2
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001, 2003 VLC authors and VideoLAN
5
 * $Id$
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
9
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
10
11
12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13
14
15
16
 * (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
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
17
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
20
21
22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
24
 *****************************************************************************/

Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
25
26
27
28
29
30
31
32
/*****************************************************************************
 * NOTA BENE: this module requires the linking against a library which is
 * known to require licensing under the GNU General Public License version 2
 * (or later). Therefore, the result of compiling this module will normally
 * be subject to the terms of that later license.
 *****************************************************************************/


33
34
35
36
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

37
#include <vlc_common.h>
38
#include <vlc_plugin.h>
39
#include <vlc_input.h>
zorglub's avatar
zorglub committed
40
#include <vlc_codec.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
41
#include <vlc_cpu.h>
42
43
44
45
46
47
48

#include <faad.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open( vlc_object_t * );
49
static void Close( vlc_object_t * );
50

51
52
53
54
55
56
57
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 ()
58
59
60
61

/****************************************************************************
 * Local prototypes
 ****************************************************************************/
62
static block_t *DecodeBlock( decoder_t *, block_t ** );
63
static void DoReordering( uint32_t *, uint32_t *, int, int, uint32_t * );
gbazin's avatar
   
gbazin committed
64
65

#define MAX_CHANNEL_POSITIONS 9
66
67
68
69
70
71
72

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

    /* samples */
73
    date_t date;
74
75

    /* temporary buffer */
gbazin's avatar
   
gbazin committed
76
77
    uint8_t *p_buffer;
    int     i_buffer;
78
    size_t  i_buffer_size;
79

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

83
    bool b_sbr, b_ps;
84
85
};

gbazin's avatar
   
gbazin committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
    };
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
118

119
/*****************************************************************************
gbazin's avatar
   
gbazin committed
120
 * OpenDecoder: probe the decoder and return score
121
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
122
static int Open( vlc_object_t *p_this )
123
{
gbazin's avatar
   
gbazin committed
124
    decoder_t *p_dec = (decoder_t*)p_this;
ivoire's avatar
ivoire committed
125
    decoder_sys_t *p_sys;
126
127
    faacDecConfiguration *cfg;

128
    if( p_dec->fmt_in.i_codec != VLC_CODEC_MP4A )
129
    {
gbazin's avatar
   
gbazin committed
130
131
132
133
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
134
    if( ( p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) ) ) == NULL )
135
        return VLC_ENOMEM;
136
137
138
139

    /* Open a faad context */
    if( ( p_sys->hfaad = faacDecOpen() ) == NULL )
    {
bigben's avatar
bigben committed
140
        msg_Err( p_dec, "cannot initialize faad" );
ivoire's avatar
ivoire committed
141
        free( p_sys );
142
143
144
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
145
    /* Misc init */
146
    date_Set( &p_sys->date, 0 );
gbazin's avatar
   
gbazin committed
147
    p_dec->fmt_out.i_cat = AUDIO_ES;
148

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
149
    p_dec->fmt_out.i_codec = HAVE_FPU ? VLC_CODEC_FL32 : VLC_CODEC_S16N;
gbazin's avatar
   
gbazin committed
150
151
    p_dec->pf_decode_audio = DecodeBlock;

gbazin's avatar
   
gbazin committed
152
153
154
    p_dec->fmt_out.audio.i_physical_channels =
        p_dec->fmt_out.audio.i_original_channels = 0;

gbazin's avatar
   
gbazin committed
155
    if( p_dec->fmt_in.i_extra > 0 )
156
157
    {
        /* We have a decoder config so init the handle */
gbazin's avatar
   
gbazin committed
158
159
        unsigned long i_rate;
        unsigned char i_channels;
160

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

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

gbazin's avatar
   
gbazin committed
185
    /* Set the faad config */
186
    cfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
187
    cfg->outputFormat = HAVE_FPU ? FAAD_FMT_FLOAT : FAAD_FMT_16BIT;
188
189
190
    faacDecSetConfiguration( p_sys->hfaad, cfg );

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

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

197
    p_sys->b_sbr = p_sys->b_ps = false;
198
199
200
201
    return VLC_SUCCESS;
}

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

209
210
211
    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
212

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

219
220
221
222
223
224
225
226
227
228
229
    /* 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 )
            {
230
                p_block->p_buffer += i_header_size;
231
232
233
234
235
                p_block->i_buffer -= i_header_size;
            }
        }
    }

236
237
238
    /* Append the block to the temporary buffer */
    if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer )
    {
239
240
241
242
243
244
245
246
247
248
249
        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;
        }
250
251
    }

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

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

276
            date_Init( &p_sys->date, i_rate, 1 );
277
278
279
        }
    }

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

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

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

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

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

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

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

328
            if( frame.error == 21 || frame.error == 12 )
329
330
            {
                /*
331
332
                 * Once an "Unexpected channel configuration change"
                 * or a "Invalid number of channels" error
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
367
368
369
                 * 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
370
            /* Flush the buffer */
371
            p_sys->i_buffer = 0;
372
            block_Release( p_block );
gbazin's avatar
   
gbazin committed
373
            return NULL;
374
        }
gbazin's avatar
   
gbazin committed
375

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

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

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

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

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

gbazin's avatar
   
gbazin committed
414
415
        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
416

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

424
425
426
            msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)",
                    psz_ext, frame.channels, frame.samplerate );

427
428
429
430
431
            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 );

432
433
            p_sys->b_sbr = b_sbr;
            p_sys->b_ps = frame.ps;
434
        }
gbazin's avatar
   
gbazin committed
435
436

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

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

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

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

gbazin's avatar
   
gbazin committed
497
        return p_out;
498
499
    }

500
    block_Release( p_block );
gbazin's avatar
   
gbazin committed
501
    return NULL;
502
503
504
}

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

    faacDecClose( p_sys->hfaad );
ivoire's avatar
ivoire committed
513
    free( p_sys->p_buffer );
514
515
    free( p_sys );
}
gbazin's avatar
   
gbazin committed
516
517
518
519
520

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

    /* Find the channels mapping */
528
    for( i = 0, j = 0; i < MAX_CHANNEL_POSITIONS; i++ )
gbazin's avatar
   
gbazin committed
529
    {
530
        for( k = 0; k < i_nb_channels; k++ )
gbazin's avatar
   
gbazin committed
531
532
533
534
535
536
537
538
539
540
        {
            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
541
    if( HAVE_FPU )
542
543
544
545
546
547
548
549
550
        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
551
}
552