diff options
Diffstat (limited to 'libavcodec/libvorbis.c')
-rw-r--r-- | libavcodec/libvorbis.c | 218 |
1 files changed, 207 insertions, 11 deletions
diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 1d7b7ef..ba786e8 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -1,20 +1,20 @@ /* * copyright (c) 2002 Mark Hills <mark@pogo.org.uk> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg 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.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -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 */ @@ -118,14 +119,14 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi, /* variable bitrate by estimate, disable slow rate management */ if (minrate == -1 && maxrate == -1) if ((ret = vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, NULL))) - goto error; + goto error; /* should not happen */ } /* cutoff frequency */ if (avctx->cutoff > 0) { cfreq = avctx->cutoff / 1000.0; if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq))) - goto error; + goto error; /* should not happen */ } /* impulse block bias */ @@ -134,6 +135,35 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi, goto error; } + if (avctx->channels == 3 && + avctx->channel_layout != (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) || + avctx->channels == 4 && + avctx->channel_layout != AV_CH_LAYOUT_2_2 && + avctx->channel_layout != AV_CH_LAYOUT_QUAD || + avctx->channels == 5 && + avctx->channel_layout != AV_CH_LAYOUT_5POINT0 && + avctx->channel_layout != AV_CH_LAYOUT_5POINT0_BACK || + avctx->channels == 6 && + avctx->channel_layout != AV_CH_LAYOUT_5POINT1 && + avctx->channel_layout != AV_CH_LAYOUT_5POINT1_BACK || + avctx->channels == 7 && + avctx->channel_layout != (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) || + avctx->channels == 8 && + avctx->channel_layout != AV_CH_LAYOUT_7POINT1) { + if (avctx->channel_layout) { + char name[32]; + av_get_channel_layout_string(name, sizeof(name), avctx->channels, + avctx->channel_layout); + av_log(avctx, AV_LOG_ERROR, "%s not supported by Vorbis: " + "output stream will have incorrect " + "channel layout.\n", name); + } else { + av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The encoder " + "will use Vorbis channel layout for " + "%d channels.\n", avctx->channels); + } + } + if ((ret = vorbis_encode_setup_init(vi))) goto error; @@ -196,7 +226,8 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avctx) } vorbis_comment_init(&s->vc); - vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT); + if (!(avctx->flags & CODEC_FLAG_BITEXACT)) + vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT); if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm, &header_code))) { @@ -302,7 +333,7 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, /* add any available packets to the output packet buffer */ while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) { if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) { - av_log(avctx, AV_LOG_ERROR, "packet buffer is too small"); + av_log(avctx, AV_LOG_ERROR, "packet buffer is too small\n"); return AVERROR_BUG; } av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL); @@ -324,10 +355,8 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL); - if ((ret = ff_alloc_packet(avpkt, op.bytes))) { - av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); + if ((ret = ff_alloc_packet2(avctx, avpkt, op.bytes))) return ret; - } av_fifo_generic_read(s->pkt_fifo, avpkt->data, op.bytes, NULL); avpkt->pts = ff_samples_to_time_base(avctx, op.granulepos); @@ -363,3 +392,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; i<op->bytes; 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, +} ; + |