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