This source file includes following definitions.
- VORB_AttachStream
- VORB_DetachStream
- VORB_GetCapabilities
- VORB_SetCapabilities
- vorbis_to_intern
- VORB_ProcessData
- VORB_GetCodecName
- NewVorbisDecoder
- DeleteVorbisDecoder
#include "ogg_in.h"
#ifdef GPAC_HAS_VORBIS
#include <vorbis/codec.h>
typedef struct
{
vorbis_info vi;
vorbis_dsp_state vd;
vorbis_block vb;
vorbis_comment vc;
ogg_packet op;
u16 ES_ID;
Bool has_reconfigured;
} VorbDec;
#define VORBISCTX() VorbDec *ctx = (VorbDec *) ((OGGWraper *)ifcg->privateStack)->opaque
static GF_Err VORB_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd)
{
ogg_packet oggpacket;
GF_BitStream *bs;
VORBISCTX();
if (ctx->ES_ID) return GF_BAD_PARAM;
if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) 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], "vorbis", 6)) return GF_NON_COMPLIANT_BITSTREAM;
ctx->ES_ID = esd->ESID;
vorbis_info_init(&ctx->vi);
vorbis_comment_init(&ctx->vc);
oggpacket.granulepos = -1;
oggpacket.b_o_s = 1;
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
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 (vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &oggpacket) < 0 ) {
gf_free(oggpacket.packet);
gf_bs_del(bs);
return GF_NON_COMPLIANT_BITSTREAM;
}
gf_free(oggpacket.packet);
}
vorbis_synthesis_init(&ctx->vd, &ctx->vi);
vorbis_block_init(&ctx->vd, &ctx->vb);
gf_bs_del(bs);
return GF_OK;
}
static GF_Err VORB_DetachStream(GF_BaseDecoder *ifcg, u16 ES_ID)
{
VORBISCTX();
if (ctx->ES_ID != ES_ID) return GF_BAD_PARAM;
vorbis_block_clear(&ctx->vb);
vorbis_dsp_clear(&ctx->vd);
vorbis_info_clear(&ctx->vi);
vorbis_comment_clear(&ctx->vc);
ctx->ES_ID = 0;
return GF_OK;
}
static GF_Err VORB_GetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability *capability)
{
VORBISCTX();
switch (capability->CapCode) {
case GF_CODEC_RESILIENT:
capability->cap.valueInt = 1;
break;
case GF_CODEC_OUTPUT_SIZE:
capability->cap.valueInt = vorbis_info_blocksize(&ctx->vi, 1) * 2 * ctx->vi.channels;
break;
case GF_CODEC_SAMPLERATE:
capability->cap.valueInt = ctx->vi.rate;
break;
case GF_CODEC_NB_CHAN:
capability->cap.valueInt = ctx->vi.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 = ctx->vi.rate / 4 / vorbis_info_blocksize(&ctx->vi, 0);
break;
case GF_CODEC_CU_DURATION:
capability->cap.valueInt = 0;
break;
case GF_CODEC_PADDING_BYTES:
capability->cap.valueInt = 0;
break;
case GF_CODEC_CHANNEL_CONFIG:
switch (ctx->vi.channels) {
case 1:
capability->cap.valueInt = GF_AUDIO_CH_FRONT_CENTER;
break;
case 2:
capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
break;
case 3:
capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER;
break;
case 4:
capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_BACK_LEFT | GF_AUDIO_CH_BACK_RIGHT;
break;
case 5:
capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_BACK_LEFT | GF_AUDIO_CH_BACK_RIGHT;
break;
case 6:
capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_BACK_LEFT | GF_AUDIO_CH_BACK_RIGHT | GF_AUDIO_CH_LFE;
break;
}
break;
default:
capability->cap.valueInt = 0;
break;
}
return GF_OK;
}
static GF_Err VORB_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capability)
{
return GF_NOT_SUPPORTED;
}
static GFINLINE void vorbis_to_intern(u32 samples, Float **pcm, char *buf, u32 channels)
{
u32 i, j;
s32 val;
ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ;
Float *mono;
for (i=0 ; i<channels ; i++) {
ptr = &data[i];
if (channels>2) {
if (i==1) ptr = &data[2];
else if (i==2) ptr = &data[1];
if ((channels==6) && (i>3)) {
if (i==6) ptr = &data[4];
else ptr = &data[i+1];
}
}
mono = pcm[i];
for (j=0; j<samples; j++) {
val = (s32) (mono[j] * 32767.f);
if (val > 32767) val = 32767;
if (val < -32768) val = -32768;
*ptr = val;
ptr += channels;
}
}
}
static GF_Err VORB_ProcessData(GF_MediaDecoder *ifcg,
char *inBuffer, u32 inBufferLength,
u16 ES_ID, u32 *CTS,
char *outBuffer, u32 *outBufferLength,
u8 PaddingBits, u32 mmlevel)
{
ogg_packet op;
Float **pcm;
u32 samples, total_samples, total_bytes;
VORBISCTX();
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 (vorbis_synthesis(&ctx->vb, &op) == 0)
vorbis_synthesis_blockin(&ctx->vd, &ctx->vb) ;
total_samples = 0;
total_bytes = 0;
while ((samples = vorbis_synthesis_pcmout(&ctx->vd, &pcm)) > 0) {
vorbis_to_intern(samples, pcm, (char*) outBuffer + total_bytes, ctx->vi.channels);
total_bytes += samples * 2 * ctx->vi.channels;
total_samples += samples;
vorbis_synthesis_read(&ctx->vd, samples);
}
*outBufferLength = total_bytes;
return GF_OK;
}
static const char *VORB_GetCodecName(GF_BaseDecoder *dec)
{
return "Vorbis Decoder";
}
u32 NewVorbisDecoder(GF_BaseDecoder *ifcd)
{
VorbDec *dec;
GF_SAFEALLOC(dec, VorbDec);
((OGGWraper *)ifcd->privateStack)->opaque = dec;
((OGGWraper *)ifcd->privateStack)->type = OGG_VORBIS;
ifcd->AttachStream = VORB_AttachStream;
ifcd->DetachStream = VORB_DetachStream;
ifcd->GetCapabilities = VORB_GetCapabilities;
ifcd->SetCapabilities = VORB_SetCapabilities;
((GF_MediaDecoder*)ifcd)->ProcessData = VORB_ProcessData;
ifcd->GetName = VORB_GetCodecName;
return 1;
}
void DeleteVorbisDecoder(GF_BaseDecoder *ifcg)
{
VorbDec *ctx;
if (!ifcg || !ifcg->privateStack)
return;
ctx = (VorbDec *) ((OGGWraper *)ifcg->privateStack)->opaque;
if (ctx) {
gf_free(ctx);
((OGGWraper *)ifcg->privateStack)->opaque = NULL;
}
}
#endif