root/modules/ogg/theora_dec.c

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

DEFINITIONS

This source file includes following definitions.
  1. THEO_AttachStream
  2. THEO_DetachStream
  3. THEO_GetCapabilities
  4. THEO_SetCapabilities
  5. THEO_ProcessData
  6. THEO_GetCodecName
  7. NewTheoraDecoder
  8. DeleteTheoraDecoder

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / XIPH.org 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 "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 unsupported to avoid confusion by the player (like SR changing ...) */
        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();
        /*not using scalabilty*/
        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;
        /*setup our own interface*/
        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


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