faad.c 10.8 KB
Newer Older
1 2 3
/*
 * Faad decoder
 * Copyright (c) 2003 Zdenek Kabelac.
4
 * Copyright (c) 2004 Thomas Raivio.
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library 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 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 20 21 22 23 24 25 26 27 28 29 30
 */

/**
 * @file faad.c
 * AAC decoder.
 *
 * still a bit unfinished - but it plays something
 */

#include "avcodec.h"
#include "faad.h"

31 32 33 34
#ifndef FAADAPI
#define FAADAPI
#endif

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/*
 * when CONFIG_FAADBIN is defined the libfaad will be opened at runtime
 */
//#undef CONFIG_FAADBIN
//#define CONFIG_FAADBIN

#ifdef CONFIG_FAADBIN
#include <dlfcn.h>
static const char* libfaadname = "libfaad.so.0";
#else
#define dlopen(a)
#define dlclose(a)
#endif

typedef struct {
50 51
    void* handle;               /* dlopen handle */
    void* faac_handle;          /* FAAD library handle */
52
    int sample_size;
53
    int init;
54 55 56 57

    /* faad calls */
    faacDecHandle FAADAPI (*faacDecOpen)(void);
    faacDecConfigurationPtr FAADAPI (*faacDecGetCurrentConfiguration)(faacDecHandle hDecoder);
58
#ifndef FAAD2_VERSION
59
        int FAADAPI (*faacDecSetConfiguration)(faacDecHandle hDecoder,
60
                                           faacDecConfigurationPtr config);
61 62 63 64 65
        int FAADAPI (*faacDecInit)(faacDecHandle hDecoder,
                                unsigned char *buffer,
                                unsigned long *samplerate,
                                unsigned long *channels);
        int FAADAPI (*faacDecInit2)(faacDecHandle hDecoder, unsigned char *pBuffer,
66 67
                                unsigned long SizeOfDecoderSpecificInfo,
                                unsigned long *samplerate, unsigned long *channels);
68 69 70 71
        int FAADAPI (*faacDecDecode)(faacDecHandle hDecoder,
                                unsigned char *buffer,
                                unsigned long *bytesconsumed,
                                short *sample_buffer,
72 73
                                unsigned long *samples);
#else
74
        unsigned char FAADAPI (*faacDecSetConfiguration)(faacDecHandle hDecoder,
75
                                                     faacDecConfigurationPtr config);
76 77 78 79 80 81
        long FAADAPI (*faacDecInit)(faacDecHandle hDecoder,
                                   unsigned char *buffer,
                                 unsigned long buffer_size,
                                 unsigned long *samplerate,
                                 unsigned char *channels);
        char FAADAPI (*faacDecInit2)(faacDecHandle hDecoder, unsigned char *pBuffer,
82 83
                                 unsigned long SizeOfDecoderSpecificInfo,
                                 unsigned long *samplerate, unsigned char *channels);
84 85 86 87 88
        void *FAADAPI (*faacDecDecode)(faacDecHandle hDecoder,
                                         faacDecFrameInfo *hInfo,
                                         unsigned char *buffer,
                                                                 unsigned long buffer_size);
        char* FAADAPI (*faacDecGetErrorMessage)(unsigned char errcode);
89
#endif
90

91
    void FAADAPI (*faacDecClose)(faacDecHandle hDecoder);
92 93


94 95 96 97 98 99 100 101 102 103 104 105
} FAACContext;

static const unsigned long faac_srates[] =
{
    96000, 88200, 64000, 48000, 44100, 32000,
    24000, 22050, 16000, 12000, 11025, 8000
};

static int faac_init_mp4(AVCodecContext *avctx)
{
    FAACContext *s = (FAACContext *) avctx->priv_data;
    unsigned long samplerate;
106 107 108
#ifndef FAAD2_VERSION
    unsigned long channels;
#else
109
    unsigned char channels;
110
#endif
111 112
    int r = 0;

113
    if (avctx->extradata){
114 115 116
        r = s->faacDecInit2(s->faac_handle, (uint8_t*) avctx->extradata,
                            avctx->extradata_size,
                            &samplerate, &channels);
117 118 119 120 121 122 123 124 125 126
        if (r < 0){
            av_log(avctx, AV_LOG_ERROR,
                   "faacDecInit2 failed r:%d   sr:%ld  ch:%ld  s:%d\n",
                   r, samplerate, (long)channels, avctx->extradata_size);
        } else {
            avctx->sample_rate = samplerate;
            avctx->channels = channels;
            s->init = 1;
        }
    }
127

128 129 130 131 132 133 134 135
    return r;
}

static int faac_decode_frame(AVCodecContext *avctx,
                             void *data, int *data_size,
                             uint8_t *buf, int buf_size)
{
    FAACContext *s = (FAACContext *) avctx->priv_data;
136 137 138 139 140 141
#ifndef FAAD2_VERSION
    unsigned long bytesconsumed;
    short *sample_buffer = NULL;
    unsigned long samples;
    int out;
#else
142
    faacDecFrameInfo frame_info;
143 144 145
    void *out;
#endif
    if(buf_size == 0)
146
        return 0;
147
#ifndef FAAD2_VERSION
148 149 150 151
    out = s->faacDecDecode(s->faac_handle,
                           (unsigned char*)buf,
                           &bytesconsumed,
                           data,
152 153 154
                           &samples);
    samples *= s->sample_size;
    if (data_size)
155
        *data_size = samples;
156
    return (buf_size < (int)bytesconsumed)
157
        ? buf_size : (int)bytesconsumed;
158
#else
159

160 161 162
    if(!s->init){
        unsigned long srate;
        unsigned char channels;
163
        int r = s->faacDecInit(s->faac_handle, buf, buf_size, &srate, &channels);
164 165 166
        if(r < 0){
            av_log(avctx, AV_LOG_ERROR, "faac: codec init failed: %s\n",
                   s->faacDecGetErrorMessage(frame_info.error));
167
            return -1;
168 169 170 171 172 173
        }
        avctx->sample_rate = srate;
        avctx->channels = channels;
        s->init = 1;
    }

174
    out = s->faacDecDecode(s->faac_handle, &frame_info, (unsigned char*)buf, (unsigned long)buf_size);
175 176

    if (frame_info.error > 0) {
177 178
        av_log(avctx, AV_LOG_ERROR, "faac: frame decoding failed: %s\n",
                s->faacDecGetErrorMessage(frame_info.error));
179
        return -1;
180 181 182 183 184 185
    }

    frame_info.samples *= s->sample_size;
    memcpy(data, out, frame_info.samples); // CHECKME - can we cheat this one

    if (data_size)
186
        *data_size = frame_info.samples;
187 188

    return (buf_size < (int)frame_info.bytesconsumed)
189
        ? buf_size : (int)frame_info.bytesconsumed;
190
#endif
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
}

static int faac_decode_end(AVCodecContext *avctx)
{
    FAACContext *s = (FAACContext *) avctx->priv_data;

    if (s->faacDecClose)
        s->faacDecClose(s->faac_handle);

    dlclose(s->handle);
    return 0;
}

static int faac_decode_init(AVCodecContext *avctx)
{
    FAACContext *s = (FAACContext *) avctx->priv_data;
    faacDecConfigurationPtr faac_cfg;

#ifdef CONFIG_FAADBIN
    const char* err = 0;

    s->handle = dlopen(libfaadname, RTLD_LAZY);
    if (!s->handle)
    {
215 216
        av_log(avctx, AV_LOG_ERROR, "FAAD library: %s could not be opened! \n%s\n",
                libfaadname, dlerror());
217 218 219 220 221 222 223 224 225 226 227
        return -1;
    }
#define dfaac(a, b) \
    do { static const char* n = "faacDec" #a; \
    if ((s->faacDec ## a = b dlsym( s->handle, n )) == NULL) { err = n; break; } } while(0)
    for(;;) {
#else  /* !CONFIG_FAADBIN */
#define dfaac(a, b)     s->faacDec ## a = faacDec ## a
#endif /* CONFIG_FAADBIN */

        // resolve all needed function calls
228 229 230
        dfaac(Open, (faacDecHandle FAADAPI (*)(void)));
        dfaac(GetCurrentConfiguration, (faacDecConfigurationPtr
                                        FAADAPI (*)(faacDecHandle)));
231
#ifndef FAAD2_VERSION
232 233
        dfaac(SetConfiguration, (int FAADAPI (*)(faacDecHandle,
                                                           faacDecConfigurationPtr)));
234

235 236
        dfaac(Init, (int FAADAPI (*)(faacDecHandle, unsigned char*,
                                     unsigned long*, unsigned long*)));
237
    dfaac(Init2, (int FAADAPI (*)(faacDecHandle, unsigned char*,
238 239
                                       unsigned long, unsigned long*,
                                       unsigned long*)));
240
    dfaac(Close, (void FAADAPI (*)(faacDecHandle hDecoder)));
241 242
        dfaac(Decode, (int FAADAPI (*)(faacDecHandle, unsigned char*,
                             unsigned long*, short*, unsigned long*)));
243
#else
244 245 246 247 248 249 250 251 252 253
        dfaac(SetConfiguration, (unsigned char FAADAPI (*)(faacDecHandle,
                                                           faacDecConfigurationPtr)));
        dfaac(Init, (long FAADAPI (*)(faacDecHandle, unsigned char*,
                                     unsigned long, unsigned long*, unsigned char*)));
        dfaac(Init2, (char FAADAPI (*)(faacDecHandle, unsigned char*,
                                       unsigned long, unsigned long*,
                                       unsigned char*)));
        dfaac(Decode, (void *FAADAPI (*)(faacDecHandle, faacDecFrameInfo*,
                             unsigned char*, unsigned long)));
        dfaac(GetErrorMessage, (char* FAADAPI (*)(unsigned char)));
254
#endif
255 256 257 258 259 260 261
#undef dfacc

#ifdef CONFIG_FAADBIN
        break;
    }
    if (err) {
        dlclose(s->handle);
262 263
        av_log(avctx, AV_LOG_ERROR, "FAAD library: cannot resolve %s in %s!\n",
                err, libfaadname);
264 265 266 267 268 269
        return -1;
    }
#endif

    s->faac_handle = s->faacDecOpen();
    if (!s->faac_handle) {
270
        av_log(avctx, AV_LOG_ERROR, "FAAD library: cannot create handler!\n");
271 272 273 274 275 276 277 278
        faac_decode_end(avctx);
        return -1;
    }


    faac_cfg = s->faacDecGetCurrentConfiguration(s->faac_handle);

    if (faac_cfg) {
279 280 281 282
        switch (avctx->bits_per_sample) {
        case 8: av_log(avctx, AV_LOG_ERROR, "FAADlib unsupported bps %d\n", avctx->bits_per_sample); break;
        default:
        case 16:
283
#ifdef FAAD2_VERSION
284
            faac_cfg->outputFormat = FAAD_FMT_16BIT;
285
#endif
286 287 288
            s->sample_size = 2;
            break;
        case 24:
289
#ifdef FAAD2_VERSION
290
            faac_cfg->outputFormat = FAAD_FMT_24BIT;
291
#endif
292 293 294
            s->sample_size = 3;
            break;
        case 32:
295
#ifdef FAAD2_VERSION
296
            faac_cfg->outputFormat = FAAD_FMT_32BIT;
297
#endif
298 299 300
            s->sample_size = 4;
            break;
        }
301

302 303
        faac_cfg->defSampleRate = (!avctx->sample_rate) ? 44100 : avctx->sample_rate;
        faac_cfg->defObjectType = LC;
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    }

    s->faacDecSetConfiguration(s->faac_handle, faac_cfg);

    faac_init_mp4(avctx);

    return 0;
}

#define AAC_CODEC(id, name)     \
AVCodec name ## _decoder = {    \
    #name,                      \
    CODEC_TYPE_AUDIO,           \
    id,                         \
    sizeof(FAACContext),        \
    faac_decode_init,           \
    NULL,                       \
    faac_decode_end,            \
    faac_decode_frame,          \
}

// FIXME - raw AAC files - maybe just one entry will be enough
AAC_CODEC(CODEC_ID_AAC, aac);
// If it's mp4 file - usually embeded into Qt Mov
AAC_CODEC(CODEC_ID_MPEG4AAC, mpeg4aac);

#undef AAC_CODEC