This source file includes following definitions.
- MAD_AttachStream
 
- MAD_DetachStream
 
- MAD_GetCapabilities
 
- MAD_SetCapabilities
 
- MAD_ProcessData
 
- MAD_GetCodecName
 
- MAD_CanHandleStream
 
- NewMADDec
 
- DeleteMADDec
 
#include <gpac/setup.h>
#ifdef GPAC_HAS_MAD
#include <gpac/modules/codec.h>
#include <gpac/constants.h>
#if defined(_WIN32_WCE) || defined(_WIN64) || defined(__SYMBIAN32__)
#ifndef FPM_DEFAULT
#define FPM_DEFAULT
#endif
#endif
#include <mad.h>
#if !defined(__GNUC__)
# if defined(_WIN32_WCE) || defined (WIN32)
#  pragma comment(lib, "libmad")
# endif
#endif
typedef struct
{
        Bool configured;
        u32 sample_rate, out_size, num_samples;
        u8 num_channels;
        
        u16 ES_ID;
        u32 cb_size, cb_trig;
        unsigned char *buffer;
        u32 len;
        Bool first;
        struct mad_frame frame;
        struct mad_stream stream;
        struct mad_synth synth;
} MADDec;
#define MADCTX() MADDec *ctx = NULL; if (ifcg) { ctx = (MADDec *) ifcg->privateStack; }
static GF_Err MAD_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd)
{
        MADCTX();
        assert( ctx );
        if (ctx->ES_ID && ctx->ES_ID!=esd->ESID) return GF_NOT_SUPPORTED;
        if (ctx->configured) {
                mad_stream_finish(&ctx->stream);
                mad_frame_finish(&ctx->frame);
                mad_synth_finish(&ctx->synth);
        }
        mad_stream_init(&ctx->stream);
        mad_frame_init(&ctx->frame);
        mad_synth_init(&ctx->synth);
        ctx->configured = GF_TRUE;
        ctx->buffer = (unsigned char*)gf_malloc(sizeof(char) * 2*MAD_BUFFER_MDLEN);
        
        ctx->num_samples = 1152;
        ctx->num_channels = 0;
        ctx->sample_rate = 0;
        ctx->out_size = 2 * ctx->num_samples * ctx->num_channels;
        ctx->ES_ID = esd->ESID;
        ctx->first = GF_TRUE;
        return GF_OK;
}
static GF_Err MAD_DetachStream(GF_BaseDecoder *ifcg, u16 ES_ID)
{
        MADCTX();
        assert( ctx );
        if (ES_ID != ctx->ES_ID) return GF_BAD_PARAM;
        assert( ifcg );
        assert( ctx );
        ctx->ES_ID = 0;
        if (ctx->buffer) gf_free(ctx->buffer);
        ctx->buffer = NULL;
        ctx->sample_rate = ctx->out_size = ctx->num_samples = 0;
        ctx->num_channels = 0;
        if (ctx->configured) {
                mad_stream_finish(&ctx->stream);
                mad_frame_finish(&ctx->frame);
                mad_synth_finish(&ctx->synth);
        }
        ctx->configured = GF_FALSE;
        return GF_OK;
}
static GF_Err MAD_GetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability *capability)
{
        MADCTX();
        assert( ctx );
        switch (capability->CapCode) {
        
        case GF_CODEC_RESILIENT:
                capability->cap.valueInt = 1;
                break;
        case GF_CODEC_OUTPUT_SIZE:
                capability->cap.valueInt = ctx->out_size;
                break;
        case GF_CODEC_SAMPLERATE:
                capability->cap.valueInt = ctx->sample_rate;
                break;
        case GF_CODEC_NB_CHAN:
                capability->cap.valueInt = ctx->num_channels;
                break;
        case GF_CODEC_BITS_PER_SAMPLE:
                capability->cap.valueInt = 16;
                break;
        case GF_CODEC_BUFFER_MIN:
                capability->cap.valueInt = ctx->cb_trig;
                break;
        case GF_CODEC_BUFFER_MAX:
                capability->cap.valueInt = ctx->cb_size;
                break;
        
        case GF_CODEC_CU_DURATION:
                capability->cap.valueInt = ctx->num_samples;
                break;
        case GF_CODEC_PADDING_BYTES:
                capability->cap.valueInt = 0;
                break;
        case GF_CODEC_CHANNEL_CONFIG:
                if (ctx->num_channels==1) {
                        capability->cap.valueInt = GF_AUDIO_CH_FRONT_CENTER;
                } else {
                        capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
                }
                break;
        default:
                capability->cap.valueInt = 0;
                break;
        }
        return GF_OK;
}
static GF_Err MAD_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capability)
{
        MADCTX();
        assert( ctx );
        switch (capability.CapCode) {
        
        case GF_CODEC_WAIT_RAP:
                ctx->first = GF_TRUE;
                ctx->len = 0;
                if (ctx->configured) {
                        mad_stream_finish(&ctx->stream);
                        mad_frame_finish(&ctx->frame);
                        mad_synth_finish(&ctx->synth);
                        mad_stream_finish(&ctx->stream);
                        mad_frame_finish(&ctx->frame);
                        mad_synth_finish(&ctx->synth);
                }
                return GF_OK;
        default:
                
                return GF_NOT_SUPPORTED;
        }
}
#define MAD_SCALE(ret, s_chan)  \
        chan = s_chan;                          \
        chan += (1L << (MAD_F_FRACBITS - 16));          \
        if (chan >= MAD_F_ONE)                                  \
                chan = MAD_F_ONE - 1;                                   \
        else if (chan < -MAD_F_ONE)                             \
                chan = -MAD_F_ONE;                              \
        ret = chan >> (MAD_F_FRACBITS + 1 - 16);                \
 
static GF_Err MAD_ProcessData(GF_MediaDecoder *ifcg,
                              char *inBuffer, u32 inBufferLength,
                              u16 ES_ID, u32 *CTS,
                              char *outBuffer, u32 *outBufferLength,
                              u8 PaddingBits, u32 mmlevel)
{
        mad_fixed_t *left_ch, *right_ch, chan;
        char *ptr;
        u32 num, outSize;
        MADCTX();
        assert( ctx );
        
        assert(ctx->ES_ID == ES_ID);
        if (ctx->ES_ID != ES_ID)
                return GF_BAD_PARAM;
        
        switch (mmlevel) {
        case GF_CODEC_LEVEL_SEEK:
                *outBufferLength = 0;
                return GF_OK;
        default:
                break;
        }
        if (ctx->out_size > *outBufferLength) {
                *outBufferLength = ctx->out_size;
                return GF_BUFFER_TOO_SMALL;
        }
        if (ctx->first) {
                ctx->first = GF_FALSE;
                memcpy(ctx->buffer, inBuffer, inBufferLength);
                ctx->len = inBufferLength;
                *outBufferLength = 0;
                return GF_OK;
        }
        memcpy(ctx->buffer + ctx->len, inBuffer, inBufferLength);
        ctx->len += inBufferLength;
        mad_stream_buffer(&ctx->stream, ctx->buffer, ctx->len);
        if (mad_frame_decode(&ctx->frame, &ctx->stream) == -1) {
                memcpy(ctx->buffer, inBuffer, inBufferLength);
                ctx->len = inBufferLength;
                *outBufferLength = 0;
                return GF_NON_COMPLIANT_BITSTREAM;
        }
        
        if (!ctx->sample_rate) {
                mad_synth_frame(&ctx->synth, &ctx->frame);
                ctx->len -= inBufferLength;
                ctx->sample_rate = ctx->synth.pcm.samplerate;
                ctx->num_channels = (u8) ctx->synth.pcm.channels;
                ctx->num_samples = ctx->synth.pcm.length;
                ctx->out_size = 2 * ctx->num_samples * ctx->num_channels;
                *outBufferLength = ctx->out_size;
                GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[MAD] decoder initialized - MP3 sample rate %d - %d channel(s)", ctx->sample_rate, ctx->num_channels));
                return GF_BUFFER_TOO_SMALL;
        }
        if (ctx->stream.next_frame) {
                ctx->len = (u32) (&ctx->buffer[ctx->len] - ctx->stream.next_frame);
                memmove(ctx->buffer, ctx->stream.next_frame, ctx->len);
        }
        mad_synth_frame(&ctx->synth, &ctx->frame);
        num = ctx->synth.pcm.length;
        ptr = (char *) outBuffer;
        left_ch = ctx->synth.pcm.samples[0];
        right_ch = ctx->synth.pcm.samples[1];
        outSize = 0;
        while (num--) {
                s32 rs;
                MAD_SCALE(rs, (*left_ch++) );
                *ptr = (rs >> 0) & 0xff;
                ptr++;
                *ptr = (rs >> 8) & 0xff;
                ptr++;
                outSize += 2;
                if (ctx->num_channels == 2) {
                        MAD_SCALE(rs, (*right_ch++) );
                        *ptr = (rs >> 0) & 0xff;
                        ptr++;
                        *ptr = (rs >> 8) & 0xff;
                        ptr++;
                        outSize += 2;
                }
        }
        *outBufferLength = outSize;
        return GF_OK;
}
static const char *MAD_GetCodecName(GF_BaseDecoder *dec)
{
        return "MAD " \
               MAD_VERSION;
}
static u32 MAD_CanHandleStream(GF_BaseDecoder *dec, u32 StreamType, GF_ESD *esd, u8 PL)
{
        
        if (StreamType != GF_STREAM_AUDIO) return GF_CODEC_NOT_SUPPORTED;
        
        if (!esd) return GF_CODEC_STREAM_TYPE_SUPPORTED;
        switch (esd->decoderConfig->objectTypeIndication) {
        
        case GPAC_OTI_AUDIO_MPEG2_PART3:
        
        case GPAC_OTI_AUDIO_MPEG1:
                return GF_CODEC_SUPPORTED;
        }
        return GF_CODEC_NOT_SUPPORTED;
}
GF_BaseDecoder *NewMADDec()
{
        GF_MediaDecoder *ifce;
        MADDec *dec;
        GF_SAFEALLOC(ifce, GF_MediaDecoder);
        if (!ifce) return NULL;
        GF_SAFEALLOC(dec, MADDec);
        if (!dec) {
                gf_free(ifce);
                return NULL;
        }
        GF_REGISTER_MODULE_INTERFACE(ifce, GF_MEDIA_DECODER_INTERFACE, "MAD Decoder", "gpac distribution")
        ifce->privateStack = dec;
        dec->cb_size = 12;
        dec->cb_trig = 4;
        
        ifce->AttachStream = MAD_AttachStream;
        ifce->DetachStream = MAD_DetachStream;
        ifce->GetCapabilities = MAD_GetCapabilities;
        ifce->SetCapabilities = MAD_SetCapabilities;
        ifce->GetName = MAD_GetCodecName;
        ifce->ProcessData = MAD_ProcessData;
        ifce->CanHandleStream = MAD_CanHandleStream;
        return (GF_BaseDecoder *)ifce;
}
void DeleteMADDec(GF_MediaDecoder *ifcg)
{
        MADDec *ctx;
        if (!ifcg)
                return;
        ctx = (MADDec *) ifcg->privateStack;
        ifcg->privateStack = NULL;
        if (ctx) {
                if (ctx->configured) {
                        mad_stream_finish(&ctx->stream);
                        mad_frame_finish(&ctx->frame);
                        mad_synth_finish(&ctx->synth);
                }
                ctx->configured = GF_FALSE;
                ctx->sample_rate = ctx->out_size = ctx->num_samples = 0;
                ctx->num_channels = 0;
                gf_free(ctx);
        }
        gf_free(ifcg);
}
#endif