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