root/modules/epoc_hw/epoc_codec.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. EDEC_LoadCaps
  2. EDEC_AttachStream
  3. EDEC_DetachStream
  4. EDEC_GetCapabilities
  5. EDEC_SetCapabilities
  6. EDEC_ProcessData
  7. EDEC_GetCodecName
  8. EDEC_CanHandleStream
  9. EPOC_codec_new
  10. EPOC_codec_del

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / AAC reader module
 *
 *  GPAC 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, or (at your option)
 *  any later version.
 *
 *  GPAC 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; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#include <gpac/modules/codec.h>
#include <gpac/constants.h>
#include <gpac/avparse.h>

#include <mmf/server/mmfcodec.h>
#include <mmf/plugin/mmfcodecimplementationuids.hrh>

#define KMMFFourCCCodeEAACP                     0x43414520  // ' ' 'E' 'A' 'C' 

#if defined(__SYMBIAN32__) && !defined(__SERIES60_3X__)
//codec configuration UID
#define  KUidMmfCodecAudioSettings      0x10203622
#endif

enum
{
        GF_EPOC_HAS_AMR = 1,
        GF_EPOC_HAS_AMR_WB = 1<<1,
        GF_EPOC_HAS_AAC = 1<<2,
        GF_EPOC_HAS_HEAAC = 1<<3,
        GF_EPOC_HAS_MP3 = 1<<4,
};

typedef struct
{
        u32 caps;
        Bool is_audio;

        u32 sample_rate, out_size, num_samples;
        u8 num_channels;

        const char *codec_name;
        CMMFCodec *dec;

        CMMFPtrBuffer *mmf_in, *mmf_out;
        TPtr8 ptr_in, ptr_out;
} EPOCCodec;

static void EDEC_LoadCaps(GF_BaseDecoder *ifcg)
{
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;
        CMMFCodec *codec = NULL;
        TInt err;

        ctx->caps = 0;
        /*AMR*/
        TRAP(err, codec = CMMFCodec::NewL(KMMFFourCCCodeAMR, KMMFFourCCCodePCM16));
        if (err==KErrNone) {
                ctx->caps |= GF_EPOC_HAS_AMR;
                delete codec;
        }
        /*AMR-WB*/
        TRAP(err, codec = CMMFCodec::NewL(KMMFFourCCCodeAWB, KMMFFourCCCodePCM16));
        if (err==KErrNone) {
                ctx->caps |= GF_EPOC_HAS_AMR_WB;
                delete codec;
        }
        /*AAC*/
        TRAP(err, codec = CMMFCodec::NewL(KMMFFourCCCodeAAC, KMMFFourCCCodePCM16));
        if (err==KErrNone) {
                ctx->caps |= GF_EPOC_HAS_AAC;
                delete codec;
        }
        /*HE-AAC*/
        TRAP(err, codec = CMMFCodec::NewL(KMMFFourCCCodeEAACP, KMMFFourCCCodePCM16));
        if (err==KErrNone) {
                ctx->caps |= GF_EPOC_HAS_HEAAC;
                delete codec;
        }

        /*MP3*/
        TRAP(err, codec = CMMFCodec::NewL(KMMFFourCCCodeMP3, KMMFFourCCCodePCM16));
        if (err==KErrNone) {
                ctx->caps |= GF_EPOC_HAS_MP3;
                delete codec;
        }

}


static GF_Err EDEC_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd)
{
        RArray<TInt> configParams;
        GF_M4ADecSpecInfo a_cfg;
        Bool aac_sbr_upsample;
        TInt err;
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;
        if (esd->dependsOnESID) return GF_NOT_SUPPORTED;
        if (ctx->dec) return GF_BAD_PARAM;


        /*audio decs*/
        switch (esd->decoderConfig->objectTypeIndication) {
        /*MPEG2 aac*/
        case GPAC_OTI_AUDIO_AAC_MPEG2_MP:
        case GPAC_OTI_AUDIO_AAC_MPEG2_LCP:
        case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP:
        /*MPEG4 aac*/
        case GPAC_OTI_AUDIO_AAC_MPEG4:
                if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) return GF_NON_COMPLIANT_BITSTREAM;
                if (gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg) != GF_OK) return GF_NON_COMPLIANT_BITSTREAM;

                aac_sbr_upsample = 0;
#if !defined(__SYMBIAN32__) || defined(__SERIES60_3X__)
                if (a_cfg.has_sbr && (ctx->caps & GF_EPOC_HAS_HEAAC)) {
                        TRAP(err, ctx->dec = CMMFCodec::NewL(KMMFFourCCCodeEAACP, KMMFFourCCCodePCM16));
                        if (err != KErrNone) {
                                a_cfg.has_sbr = 0;
                                goto retry_no_sbr;
                        }
                        aac_sbr_upsample = (a_cfg.base_sr<=24000) ? 1 : 0;

                        configParams.Append(a_cfg.base_sr);                                             //  0: Input Sample Frequency
                        configParams.Append(a_cfg.nb_chan);                                             //  1: Num Channels [1|2]
                        configParams.Append(1);                                                                 //  2: Input Profile Object type [1 - LC, 3 - LTP]
                        configParams.Append(aac_sbr_upsample ? 2048 : 1024);    //  3: Output Frame Size
                        configParams.Append(1024);                                                              //  4: Input Frame Len [1024, 960]
                        configParams.Append(a_cfg.base_sr);                                             //  5: Input Sample Rate
                        configParams.Append(0);                                                                 //  6: 0
                        configParams.Append(aac_sbr_upsample ? 0 : 1);                  //  7: Down Sample Mode [0|1]
                        configParams.Append(16);                                                                //  8: Sample resolution, 8Khz (8-bit PCM) or 16Khz (16-bit)
                        configParams.Append(a_cfg.sbr_sr);                                              //  9: Output Sample Frequency
                        configParams.Append(5);                                                                 // 10: Extension Object Type

                        TRAP(err, ctx->dec->ConfigureL(TUid::Uid(KUidMmfCodecAudioSettings), (TDesC8&) configParams));
                        if (err != KErrNone) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[EPOC Decoder] Failed to configure HE-AAC decoder (error %d) - retrying with AAC\n", err));
                                configParams.Reset();
                                goto retry_no_sbr;
                        }
                        ctx->codec_name = "EPOC HE-AAC Decoder";
                        ctx->num_channels = a_cfg.nb_chan;
                        ctx->num_samples = aac_sbr_upsample ? 2048 : 1024;
                        ctx->sample_rate = a_cfg.sbr_sr;
                } else
#endif
                {
retry_no_sbr:
                        TRAP(err, ctx->dec = CMMFCodec::NewL(KMMFFourCCCodeAAC, KMMFFourCCCodePCM16));
                        if (err != KErrNone) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[EPOC Decoder] Unable to load native codec: error %d\n", err));
                                return GF_IO_ERR;
                        }
                        configParams.Append(a_cfg.base_sr); // Input Sample Rate
                        configParams.Append(a_cfg.nb_chan);       // Num Channels [1|2]
                        configParams.Append((a_cfg.base_object_type==GF_M4A_AAC_LC) ? 1 : 3);       // AAC Input Profile [1 - LC, 3 - LTP]
                        configParams.Append(1024);       // Input Frame Len [1024, 960]
                        configParams.Append(0);                    // AAC Down Mixing [0-none | 1 mono | 2 stereo]
                        configParams.Append(0);                    // Aac output channels selection {0 - none, 1 - 1, 2 - 2}
                        configParams.Append(0);                    // Aac decimation factor {0 - none, 2 - decimation by 2, 4 - decimation by 4}
                        configParams.Append(0);                    // Aac concealment - It can be {0 - none, 1 - basic}
                        configParams.Append(16);     // Sample resolution - It can be {16 - 16-bit resolution}
                        configParams.Append(0);                    // Sample Rate Conversion 0 : none

                        TRAP(err, ctx->dec->ConfigureL(TUid::Uid(KUidMmfCodecAudioSettings), (TDesC8&) configParams));
                        if (err != KErrNone) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[EPOC Decoder] Failed to configure AAC decoder (error %d)\n", err));
                                return GF_NON_COMPLIANT_BITSTREAM;
                        }
                        ctx->codec_name = "EPOC AAC Decoder";
                        ctx->num_channels = a_cfg.nb_chan;
                        ctx->num_samples = 1024;
                        ctx->sample_rate = a_cfg.base_sr;
                }
                ctx->out_size = ctx->num_channels * ctx->num_samples * 2;
                break;
        /*non-mpeg4 codecs*/
        case GPAC_OTI_MEDIA_GENERIC:
                if (!esd->decoderConfig->decoderSpecificInfo || esd->decoderConfig->decoderSpecificInfo->dataLength<4) return GF_BAD_PARAM;
                if (!strnicmp(esd->decoderConfig->decoderSpecificInfo->data, "samr", 4) || !strnicmp(esd->decoderConfig->decoderSpecificInfo->data, "amr ", 4)) {
                        TRAP(err, ctx->dec = CMMFCodec::NewL(KMMFFourCCCodeAMR, KMMFFourCCCodePCM16));
                        if (err != KErrNone) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[EPOC Decoder] Unable to load native codec: error %d\n", err));
                                return GF_IO_ERR;
                        }
                        ctx->is_audio = 1;
                        ctx->num_channels = 1;
                        ctx->num_samples = 160;
                        ctx->sample_rate = 8000;
                        ctx->out_size = ctx->num_channels * ctx->num_samples * 2;
                        ctx->codec_name = "EPOC AMR Decoder";
                }
                else if (!strnicmp(esd->decoderConfig->decoderSpecificInfo->data, "sawb", 4)) {
                        TRAP(err, ctx->dec = CMMFCodec::NewL(KMMFFourCCCodeAWB, KMMFFourCCCodePCM16));
                        if (err != KErrNone) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[EPOC Decoder] Unable to load native codec: error %d\n", err));
                                return GF_IO_ERR;
                        }
                        ctx->is_audio = 1;
                        ctx->num_channels = 1;
                        ctx->num_samples = 320;
                        ctx->sample_rate = 16000;
                        ctx->out_size = ctx->num_channels * ctx->num_samples * 2;
                        ctx->codec_name = "EPOC AMR-Wideband Decoder";
                }
                break;
        default:
                return GF_BAD_PARAM;
        }

        ctx->mmf_in = CMMFPtrBuffer::NewL();
        ctx->mmf_out = CMMFPtrBuffer::NewL();

        return GF_OK;
}

static GF_Err EDEC_DetachStream(GF_BaseDecoder *ifcg, u16 ES_ID)
{
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;

        if (ctx->mmf_in) {
                delete ctx->mmf_in;
                ctx->mmf_in = NULL;
        }
        if (ctx->mmf_out) {
                delete ctx->mmf_out;
                ctx->mmf_out = NULL;
        }
        if (ctx->dec) {
                delete ctx->dec;
                ctx->dec = NULL;
        }
        return GF_OK;
}
static GF_Err EDEC_GetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability *capability)
{
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;

        switch (capability->CapCode) {
        /*not tested yet*/
        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 = 4;
                break;
        case GF_CODEC_BUFFER_MAX:
                capability->cap.valueInt = 12;
                break;
        case GF_CODEC_CU_DURATION:
                capability->cap.valueInt = ctx->num_samples;
                break;
        /*to refine, it seems that 4 bytes padding is not enough on all streams ?*/
        case GF_CODEC_PADDING_BYTES:
                capability->cap.valueInt = 4;
                break;
        case GF_CODEC_CHANNEL_CONFIG:
                capability->cap.valueInt = (ctx->num_channels==1) ? GF_AUDIO_CH_FRONT_CENTER : (GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT);
                break;
        default:
                capability->cap.valueInt = 0;
                break;
        }
        return GF_OK;
}
static GF_Err EDEC_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capability)
{
        /*return unsupported to avoid confusion by the player (like SR changing ...) */
        return GF_NOT_SUPPORTED;
}


static GF_Err EDEC_ProcessData(GF_MediaDecoder *ifcg,
                               char *inBuffer, u32 inBufferLength,
                               u16 ES_ID, u32 *CTS,
                               char *outBuffer, u32 *outBufferLength,
                               u8 PaddingBits, u32 mmlevel)
{
        TCodecProcessResult res;
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;

        if (*outBufferLength < ctx->out_size) {
                *outBufferLength = ctx->out_size;
                GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("AMR buffer too small\n"));
                return GF_BUFFER_TOO_SMALL;
        }

        ctx->ptr_in.Set((TUint8*)inBuffer, inBufferLength, inBufferLength);
        ctx->mmf_in->SetPtr(ctx->ptr_in);
        ctx->ptr_out.Set((TUint8*)outBuffer, *outBufferLength, *outBufferLength);
        ctx->mmf_out->SetPtr(ctx->ptr_out);

        TRAPD(e, res = ctx->dec->ProcessL(*ctx->mmf_in, *ctx->mmf_out));
        if (res.iStatus==TCodecProcessResult::EProcessError) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[EPOC Decoder] Decode failed - error %d\n", res.iStatus));
                return GF_NON_COMPLIANT_BITSTREAM;
        }

        return GF_OK;
}

static const char *EDEC_GetCodecName(GF_BaseDecoder *ifcg)
{
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;
        return ctx->codec_name;
}

static u32 EDEC_CanHandleStream(GF_BaseDecoder *ifcg, u32 StreamType, GF_ESD *esd, u8 PL)
{
        char *dsi;
        GF_M4ADecSpecInfo a_cfg;
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;

        /*audio decs*/
        if (StreamType == GF_STREAM_AUDIO) {
                /*media type query*/
                if (!esd) return GF_CODEC_STREAM_TYPE_SUPPORTED;
                dsi = esd->decoderConfig->decoderSpecificInfo ? esd->decoderConfig->decoderSpecificInfo->data : NULL;
                switch (esd->decoderConfig->objectTypeIndication) {
                /*MPEG2 aac*/
                case GPAC_OTI_AUDIO_AAC_MPEG2_MP:
                case GPAC_OTI_AUDIO_AAC_MPEG2_LCP:
                case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP:
                /*MPEG4 aac*/
                case GPAC_OTI_AUDIO_AAC_MPEG4:
                        if (!dsi) return GF_CODEC_NOT_SUPPORTED;
                        if (gf_m4a_get_config(dsi, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg) != GF_OK) return GF_CODEC_MAYBE_SUPPORTED;
                        switch (a_cfg.base_object_type) {
                        /*only LTP and LC supported*/
                        case GF_M4A_AAC_LC:
                        case GF_M4A_AAC_LTP:
                                if ((ctx->caps & GF_EPOC_HAS_AAC) || (ctx->caps & GF_EPOC_HAS_HEAAC) ) return GF_CODEC_SUPPORTED;
                        default:
                                break;
                        }
                        break;
                /*MPEG1 audio*/
                case GPAC_OTI_AUDIO_MPEG2_PART3:
                /*MPEG2 audio*/
                case GPAC_OTI_AUDIO_MPEG1:
                        /* NOT SUPPORTED YET if (ctx->caps & GF_EPOC_HAS_MP3) return 1; */
                        break;
                /*non-mpeg4 codecs*/
                case GPAC_OTI_MEDIA_GENERIC:
                        if (!dsi) return GF_CODEC_NOT_SUPPORTED;
                        if (esd->decoderConfig->decoderSpecificInfo->data < 4) return GF_CODEC_NOT_SUPPORTED;
                        if (!strnicmp(dsi, "samr", 4) || !strnicmp(dsi, "amr ", 4)) {
                                if (ctx->caps & GF_EPOC_HAS_AMR) return GF_CODEC_SUPPORTED;
                        }
                        if (!strnicmp(dsi, "sawb", 4)) {
                                if (ctx->caps & GF_EPOC_HAS_AMR_WB) return GF_CODEC_SUPPORTED;
                        }
                        break;
                default:
                        return GF_CODEC_NOT_SUPPORTED;
                }
        }
        return GF_CODEC_NOT_SUPPORTED;
}

#ifdef __cplusplus
extern "C" {
#endif

GF_BaseDecoder *EPOC_codec_new()
{
        GF_MediaDecoder *ifce;
        EPOCCodec *ctx;

        GF_SAFEALLOC(ifce, GF_MediaDecoder);
        GF_REGISTER_MODULE_INTERFACE(ifce, GF_MEDIA_DECODER_INTERFACE, "EPOC Native Decoder", "gpac distribution")

        GF_SAFEALLOC(ctx, EPOCCodec);
        ifce->privateStack = ctx;

        /*setup our own interface*/
        ifce->AttachStream = EDEC_AttachStream;
        ifce->DetachStream = EDEC_DetachStream;
        ifce->GetCapabilities = EDEC_GetCapabilities;
        ifce->SetCapabilities = EDEC_SetCapabilities;
        ifce->ProcessData = EDEC_ProcessData;
        ifce->CanHandleStream = EDEC_CanHandleStream;
        ifce->GetName = EDEC_GetCodecName;
        EDEC_LoadCaps((GF_BaseDecoder*)ifce);
        return (GF_BaseDecoder *) ifce;
}

void EPOC_codec_del(GF_BaseDecoder *ifcg)
{
        EPOCCodec *ctx = (EPOCCodec *)ifcg->privateStack;

        gf_free(ctx);
        gf_free(ifcg);
}


#ifdef __cplusplus
}
#endif

/* [<][>][^][v][top][bottom][index][help] */