This source file includes following definitions.
- THEO_AttachStream
 
- THEO_DetachStream
 
- THEO_GetCapabilities
 
- THEO_SetCapabilities
 
- THEO_ProcessData
 
- THEO_GetCodecName
 
- NewTheoraDecoder
 
- DeleteTheoraDecoder
 
#include "ogg_in.h"
#ifdef GPAC_HAS_THEORA
#include <theora/theora.h>
typedef struct
{
        theora_info ti;
        theora_state td;
        theora_comment tc;
        ogg_packet op;
        u16 ES_ID;
        Bool has_reconfigured;
} TheoraDec;
#define THEORACTX() TheoraDec *ctx = (TheoraDec *) ((OGGWraper *)ifcg->privateStack)->opaque
static GF_Err THEO_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd)
{
        ogg_packet oggpacket;
        GF_BitStream *bs;
        THEORACTX();
        if (ctx->ES_ID) return GF_BAD_PARAM;
        if (!esd->decoderConfig->decoderSpecificInfo) return GF_NON_COMPLIANT_BITSTREAM;
        if (esd->decoderConfig->objectTypeIndication != GPAC_OTI_MEDIA_OGG) return GF_NON_COMPLIANT_BITSTREAM;
        if ( (esd->decoderConfig->decoderSpecificInfo->dataLength<9) || strncmp(&esd->decoderConfig->decoderSpecificInfo->data[3], "theora", 6)) return GF_NON_COMPLIANT_BITSTREAM;
        oggpacket.granulepos = -1;
        oggpacket.b_o_s = 1;
        oggpacket.e_o_s = 0;
        oggpacket.packetno = 0;
        ctx->ES_ID = esd->ESID;
        theora_info_init(&ctx->ti);
        theora_comment_init(&ctx->tc);
        bs = gf_bs_new(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ);
        while (gf_bs_available(bs)) {
                oggpacket.bytes = gf_bs_read_u16(bs);
                oggpacket.packet = gf_malloc(sizeof(char) * oggpacket.bytes);
                gf_bs_read_data(bs, oggpacket.packet, oggpacket.bytes);
                if (theora_decode_header(&ctx->ti, &ctx->tc, &oggpacket) < 0 ) {
                        gf_free(oggpacket.packet);
                        gf_bs_del(bs);
                        return GF_NON_COMPLIANT_BITSTREAM;
                }
                gf_free(oggpacket.packet);
        }
        theora_decode_init(&ctx->td, &ctx->ti);
        gf_bs_del(bs);
        return GF_OK;
}
static GF_Err THEO_DetachStream(GF_BaseDecoder *ifcg, u16 ES_ID)
{
        THEORACTX();
        if (ctx->ES_ID != ES_ID) return GF_BAD_PARAM;
        theora_clear(&ctx->td);
        theora_info_clear(&ctx->ti);
        theora_comment_clear(&ctx->tc);
        ctx->ES_ID = 0;
        return GF_OK;
}
static GF_Err THEO_GetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability *capability)
{
        THEORACTX();
        switch (capability->CapCode) {
        case GF_CODEC_WIDTH:
                capability->cap.valueInt = ctx->ti.width;
                break;
        case GF_CODEC_HEIGHT:
                capability->cap.valueInt = ctx->ti.height;
                break;
        case GF_CODEC_STRIDE:
                capability->cap.valueInt = ctx->ti.width;
                break;
        case GF_CODEC_FPS:
                capability->cap.valueFloat = (Float) ctx->ti.fps_numerator;
                capability->cap.valueFloat /= ctx->ti.fps_denominator;
                break;
        case GF_CODEC_PIXEL_FORMAT:
                capability->cap.valueInt = GF_PIXEL_YV12;
                break;
        case GF_CODEC_REORDER:
                capability->cap.valueInt = 0;
                break;
        case GF_CODEC_RESILIENT:
                capability->cap.valueInt = 1;
                break;
        case GF_CODEC_OUTPUT_SIZE:
                capability->cap.valueInt = 3*ctx->ti.width * ctx->ti.height / 2;
                break;
        case GF_CODEC_BUFFER_MIN:
                capability->cap.valueInt = 1;
                break;
        case GF_CODEC_BUFFER_MAX:
                capability->cap.valueInt = 4;
                break;
        case GF_CODEC_PADDING_BYTES:
                capability->cap.valueInt = 0;
                break;
        default:
                capability->cap.valueInt = 0;
                break;
        }
        return GF_OK;
}
static GF_Err THEO_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capability)
{
        
        return GF_NOT_SUPPORTED;
}
static GF_Err THEO_ProcessData(GF_MediaDecoder *ifcg,
                               char *inBuffer, u32 inBufferLength,
                               u16 ES_ID, u32 *CTS,
                               char *outBuffer, u32 *outBufferLength,
                               u8 PaddingBits, u32 mmlevel)
{
        ogg_packet op;
        yuv_buffer yuv;
        u32 i;
        char *pYO, *pUO, *pVO;
        unsigned char *pYD, *pUD, *pVD;
        THEORACTX();
        
        assert(ctx->ES_ID == ES_ID);
        op.granulepos = -1;
        op.b_o_s = 0;
        op.e_o_s = 0;
        op.packetno = 0;
        op.packet = inBuffer;
        op.bytes = inBufferLength;
        *outBufferLength = 0;
        if (theora_decode_packetin(&ctx->td, &op)<0) return GF_NON_COMPLIANT_BITSTREAM;
        if (mmlevel     == GF_CODEC_LEVEL_SEEK) return GF_OK;
        if (theora_decode_YUVout(&ctx->td, &yuv)<0) return GF_OK;
        pYO = yuv.y;
        pUO = yuv.u;
        pVO = yuv.v;
        pYD = outBuffer;
        pUD = outBuffer + ctx->ti.width * ctx->ti.height;
        pVD = outBuffer + 5 * ctx->ti.width * ctx->ti.height / 4;
        for (i=0; i<(u32)yuv.y_height; i++) {
                memcpy(pYD, pYO, sizeof(char) * yuv.y_width);
                pYD += ctx->ti.width;
                pYO += yuv.y_stride;
                if (i%2) continue;
                memcpy(pUD, pUO, sizeof(char) * yuv.uv_width);
                memcpy(pVD, pVO, sizeof(char) * yuv.uv_width);
                pUD += ctx->ti.width/2;
                pVD += ctx->ti.width/2;
                pUO += yuv.uv_stride;
                pVO += yuv.uv_stride;
        }
        *outBufferLength = 3*ctx->ti.width*ctx->ti.height/2;
        return GF_OK;
}
static const char *THEO_GetCodecName(GF_BaseDecoder *dec)
{
        return "Theora Decoder";
}
u32 NewTheoraDecoder(GF_BaseDecoder *ifcd)
{
        TheoraDec *dec;
        GF_SAFEALLOC(dec, TheoraDec);
        ((OGGWraper *)ifcd->privateStack)->opaque = dec;
        ((OGGWraper *)ifcd->privateStack)->type = OGG_THEORA;
        
        ifcd->AttachStream = THEO_AttachStream;
        ifcd->DetachStream = THEO_DetachStream;
        ifcd->GetCapabilities = THEO_GetCapabilities;
        ifcd->SetCapabilities = THEO_SetCapabilities;
        ((GF_MediaDecoder*)ifcd)->ProcessData = THEO_ProcessData;
        ifcd->GetName = THEO_GetCodecName;
        return 1;
}
void DeleteTheoraDecoder(GF_BaseDecoder *ifcg)
{
        THEORACTX();
        gf_free(ctx);
}
#endif