faad.c 9.62 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.4 2003/11/16 21:07:30 gbazin Exp $
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * 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.
 *****************************************************************************/

#include <stdlib.h>

#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>

#include <faad.h>
#include "codecs.h"

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open( vlc_object_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
37
static void CloseDecoder( vlc_object_t * );
38 39 40 41

vlc_module_begin();
    set_description( _("AAC audio decoder (using libfaad2)") );
    set_capability( "decoder", 60 );
Gildas Bazin's avatar
 
Gildas Bazin committed
42
    set_callbacks( Open, CloseDecoder );
43 44 45 46 47 48
vlc_module_end();


/****************************************************************************
 * Local prototypes
 ****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
49
static aout_buffer_t *DecodeBlock( decoder_t *, block_t ** );
50 51 52 53 54 55 56

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

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

    /* temporary buffer */
Gildas Bazin's avatar
 
Gildas Bazin committed
60 61 62
    uint8_t *p_buffer;
    int     i_buffer;
    int     i_buffer_size;
63 64 65 66 67 68 69 70
};

static unsigned int pi_channels_maps[7] =
{
    0,
    AOUT_CHAN_CENTER,
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
    AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
Gildas Bazin's avatar
 
Gildas Bazin committed
71 72 73 74
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT |
        AOUT_CHAN_REARRIGHT,
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
        AOUT_CHAN_REARRIGHT,
75
     /* FIXME */
Gildas Bazin's avatar
 
Gildas Bazin committed
76 77
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
        AOUT_CHAN_REARRIGHT | AOUT_CHAN_REARCENTER
78 79 80
};

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
81
 * OpenDecoder: probe the decoder and return score
82
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
83
static int Open( vlc_object_t *p_this )
84
{
Gildas Bazin's avatar
 
Gildas Bazin committed
85
    decoder_t *p_dec = (decoder_t*)p_this;
86 87 88
    decoder_sys_t *p_sys = p_dec->p_sys;
    faacDecConfiguration *cfg;

Gildas Bazin's avatar
 
Gildas Bazin committed
89
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','4','a') )
90
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
91 92 93 94 95 96 97 98 99
        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;
100 101 102 103 104 105 106 107 108
    }

    /* 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
109 110 111 112 113 114 115
    /* 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;

    if( p_dec->fmt_in.i_extra > 0 )
116 117
    {
        /* We have a decoder config so init the handle */
Gildas Bazin's avatar
 
Gildas Bazin committed
118 119
        unsigned long i_rate;
        unsigned char i_channels;
120

Gildas Bazin's avatar
 
Gildas Bazin committed
121 122
        if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
                          p_dec->fmt_in.i_extra,
123 124 125 126 127
                          &i_rate, &i_channels ) < 0 )
        {
            return VLC_EGENERIC;
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
128 129 130 131 132 133 134
        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_maps[i_channels];

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

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

    /* buffer */
    p_sys->i_buffer = 0;
    p_sys->i_buffer_size = 10000;
    p_sys->p_buffer = malloc( p_sys->i_buffer_size );

    return VLC_SUCCESS;
}

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

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

    p_block = *pp_block;
169 170 171 172

    /* 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
173
        p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
174 175 176
        p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
177 178 179 180 181 182 183 184 185
    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 )
186
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
187 188
        unsigned long i_rate;
        unsigned char i_channels;
189 190 191 192 193 194

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

        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_maps[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;
218 219 220
    }

    /* Decode all data */
Gildas Bazin's avatar
 
Gildas Bazin committed
221
    if( p_sys->i_buffer )
222 223 224
    {
        void *samples;
        faacDecFrameInfo frame;
Gildas Bazin's avatar
 
Gildas Bazin committed
225
        aout_buffer_t *p_out;
226 227

        samples = faacDecDecode( p_sys->hfaad, &frame,
Gildas Bazin's avatar
 
Gildas Bazin committed
228
                                 p_sys->p_buffer, p_sys->i_buffer );
229 230 231 232

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

            /* Flush the buffer */
235
            p_sys->i_buffer = 0;
236
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
237
            return NULL;
238
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
239

240 241 242
        if( frame.channels <= 0 || frame.channels > 6 )
        {
            msg_Warn( p_dec, "invalid channels count" );
Gildas Bazin's avatar
 
Gildas Bazin committed
243 244

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

250 251 252
        if( frame.samples <= 0 )
        {
            msg_Warn( p_dec, "decoded zero samples" );
Gildas Bazin's avatar
 
Gildas Bazin committed
253 254

            /* Flush the buffer */
255
            p_sys->i_buffer = 0;
256
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
257
            return NULL;
258 259
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
260 261
        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
262
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
263 264
            aout_DateInit( &p_sys->date, frame.samplerate );
            aout_DateSet( &p_sys->date, p_block->i_pts );
265
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
266
        p_block->i_pts = 0;  /* PTS is valid only once */
267

Gildas Bazin's avatar
 
Gildas Bazin committed
268 269 270 271 272
        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
        p_dec->fmt_out.audio.i_physical_channels =
            p_dec->fmt_out.audio.i_original_channels =
                pi_channels_maps[frame.channels];
273

Gildas Bazin's avatar
 
Gildas Bazin committed
274 275 276
        p_out = p_dec->pf_aout_buffer_new( p_dec,
                                           frame.samples / frame.channels );
        if( p_out == NULL )
277
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
278
            p_sys->i_buffer = 0;
279
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
280
            return NULL;
281 282
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
283 284 285 286 287
        p_out->start_date = aout_DateGet( &p_sys->date );
        p_out->end_date = aout_DateIncrement( &p_sys->date,
                                              frame.samples / frame.channels );

        memcpy( p_out->p_buffer, samples, p_out->i_nb_bytes );
288

Gildas Bazin's avatar
 
Gildas Bazin committed
289 290
        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
291
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
292 293
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
294 295
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
296
        return p_out;
297 298
    }

299
    block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
300
    return NULL;
301 302 303
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
304
 * CloseDecoder:
305
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
306
static void CloseDecoder( vlc_object_t *p_this )
307
{
Gildas Bazin's avatar
 
Gildas Bazin committed
308
    decoder_t *p_dec = (decoder_t *)p_this;
309 310 311 312 313
    decoder_sys_t *p_sys = p_dec->p_sys;

    faacDecClose( p_sys->hfaad );
    free( p_sys );
}