From afcb67113da690dd9c56174f44a1c847ec3aa3c3 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Sat, 5 May 2012 10:45:30 +0200 Subject: Revert "Remove libvorbis Vorbis decoding support. Our native decoder is complete" Its useful to support the official decoder for comparission and debugging. This reverts commit f9def9ccc6ecfe1778d4daa62a7ada27b5f79bfc. Conflicts: Changelog configure libavcodec/allcodecs.c libavcodec/libvorbis.c Signed-off-by: Michael Niedermayer --- libavcodec/libvorbis.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) (limited to 'libavcodec/libvorbis.c') diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index db65d160a3..54e9f134ea 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -49,6 +49,7 @@ typedef struct OggVorbisContext { AVClass *av_class; /**< class for AVOptions */ + AVFrame frame; vorbis_info vi; /**< vorbis_info used during init */ vorbis_dsp_state vd; /**< DSP state used for analysis */ vorbis_block vb; /**< vorbis_block used for analysis */ @@ -390,3 +391,170 @@ AVCodec ff_libvorbis_encoder = { .priv_class = &class, .defaults = defaults, }; + +static int oggvorbis_decode_init(AVCodecContext *avccontext) { + OggVorbisContext *context = avccontext->priv_data ; + uint8_t *p= avccontext->extradata; + int i, hsizes[3]; + unsigned char *headers[3], *extradata = avccontext->extradata; + + vorbis_info_init(&context->vi) ; + vorbis_comment_init(&context->vc) ; + + if(! avccontext->extradata_size || ! p) { + av_log(avccontext, AV_LOG_ERROR, "vorbis extradata absent\n"); + return -1; + } + + if(p[0] == 0 && p[1] == 30) { + for(i = 0; i < 3; i++){ + hsizes[i] = bytestream_get_be16(&p); + headers[i] = p; + p += hsizes[i]; + } + } else if(*p == 2) { + unsigned int offset = 1; + p++; + for(i=0; i<2; i++) { + hsizes[i] = 0; + while((*p == 0xFF) && (offset < avccontext->extradata_size)) { + hsizes[i] += 0xFF; + offset++; + p++; + } + if(offset >= avccontext->extradata_size - 1) { + av_log(avccontext, AV_LOG_ERROR, + "vorbis header sizes damaged\n"); + return -1; + } + hsizes[i] += *p; + offset++; + p++; + } + hsizes[2] = avccontext->extradata_size - hsizes[0]-hsizes[1]-offset; +#if 0 + av_log(avccontext, AV_LOG_DEBUG, + "vorbis header sizes: %d, %d, %d, / extradata_len is %d \n", + hsizes[0], hsizes[1], hsizes[2], avccontext->extradata_size); +#endif + headers[0] = extradata + offset; + headers[1] = extradata + offset + hsizes[0]; + headers[2] = extradata + offset + hsizes[0] + hsizes[1]; + } else { + av_log(avccontext, AV_LOG_ERROR, + "vorbis initial header len is wrong: %d\n", *p); + return -1; + } + + for(i=0; i<3; i++){ + context->op.b_o_s= i==0; + context->op.bytes = hsizes[i]; + context->op.packet = headers[i]; + if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){ + av_log(avccontext, AV_LOG_ERROR, "%d. vorbis header damaged\n", i+1); + return -1; + } + } + + avccontext->channels = context->vi.channels; + avccontext->sample_rate = context->vi.rate; + avccontext->time_base= (AVRational){1, avccontext->sample_rate}; + + vorbis_synthesis_init(&context->vd, &context->vi); + vorbis_block_init(&context->vd, &context->vb); + + return 0 ; +} + + +static inline int conv(int samples, float **pcm, char *buf, int channels) { + int i, j; + ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ; + float *mono ; + + for(i = 0 ; i < channels ; i++){ + ptr = &data[i]; + mono = pcm[i] ; + + for(j = 0 ; j < samples ; j++) { + *ptr = av_clip_int16(mono[j] * 32767.f); + ptr += channels; + } + } + + return 0 ; +} + +static int oggvorbis_decode_frame(AVCodecContext *avccontext, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + OggVorbisContext *context = avccontext->priv_data ; + float **pcm ; + ogg_packet *op= &context->op; + int samples, total_samples, total_bytes; + int ret; + int16_t *output; + + if(!avpkt->size){ + //FIXME flush + return 0; + } + + context->frame.nb_samples = 8192*4; + if ((ret = avccontext->get_buffer(avccontext, &context->frame)) < 0) { + av_log(avccontext, AV_LOG_ERROR, "get_buffer() failed\n"); + return ret; + } + output = (int16_t *)context->frame.data[0]; + + + op->packet = avpkt->data; + op->bytes = avpkt->size; + +// av_log(avccontext, AV_LOG_DEBUG, "%d %d %d %"PRId64" %"PRId64" %d %d\n", op->bytes, op->b_o_s, op->e_o_s, op->granulepos, op->packetno, buf_size, context->vi.rate); + +/* for(i=0; ibytes; i++) + av_log(avccontext, AV_LOG_DEBUG, "%02X ", op->packet[i]); + av_log(avccontext, AV_LOG_DEBUG, "\n");*/ + + if(vorbis_synthesis(&context->vb, op) == 0) + vorbis_synthesis_blockin(&context->vd, &context->vb) ; + + total_samples = 0 ; + total_bytes = 0 ; + + while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) { + conv(samples, pcm, (char*)output + total_bytes, context->vi.channels) ; + total_bytes += samples * 2 * context->vi.channels ; + total_samples += samples ; + vorbis_synthesis_read(&context->vd, samples) ; + } + + context->frame.nb_samples = total_samples; + *got_frame_ptr = 1; + *(AVFrame *)data = context->frame; + return avpkt->size; +} + + +static int oggvorbis_decode_close(AVCodecContext *avccontext) { + OggVorbisContext *context = avccontext->priv_data ; + + vorbis_info_clear(&context->vi) ; + vorbis_comment_clear(&context->vc) ; + + return 0 ; +} + + +AVCodec ff_libvorbis_decoder = { + .name = "libvorbis", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_VORBIS, + .priv_data_size = sizeof(OggVorbisContext), + .init = oggvorbis_decode_init, + .decode = oggvorbis_decode_frame, + .close = oggvorbis_decode_close, + .capabilities = CODEC_CAP_DELAY, +} ; + -- cgit v1.2.3