1/* 2 * copyright (c) 2002 Mark Hills <mark@pogo.org.uk> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21/** 22 * @file 23 * Ogg Vorbis codec support via libvorbisenc. 24 * @author Mark Hills <mark@pogo.org.uk> 25 */ 26 27#include <vorbis/vorbisenc.h> 28 29#include "avcodec.h" 30#include "bytestream.h" 31 32#undef NDEBUG 33#include <assert.h> 34 35#define OGGVORBIS_FRAME_SIZE 64 36 37#define BUFFER_SIZE (1024*64) 38 39typedef struct OggVorbisContext { 40 vorbis_info vi ; 41 vorbis_dsp_state vd ; 42 vorbis_block vb ; 43 uint8_t buffer[BUFFER_SIZE]; 44 int buffer_index; 45 int eof; 46 47 /* decoder */ 48 vorbis_comment vc ; 49 ogg_packet op; 50} OggVorbisContext ; 51 52 53static av_cold int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) { 54 double cfreq; 55 56 if(avccontext->flags & CODEC_FLAG_QSCALE) { 57 /* variable bitrate */ 58 if(vorbis_encode_setup_vbr(vi, avccontext->channels, 59 avccontext->sample_rate, 60 avccontext->global_quality / (float)FF_QP2LAMBDA / 10.0)) 61 return -1; 62 } else { 63 /* constant bitrate */ 64 if(vorbis_encode_setup_managed(vi, avccontext->channels, 65 avccontext->sample_rate, -1, avccontext->bit_rate, -1)) 66 return -1; 67 68#ifdef OGGVORBIS_VBR_BY_ESTIMATE 69 /* variable bitrate by estimate */ 70 if(vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL)) 71 return -1; 72#endif 73 } 74 75 /* cutoff frequency */ 76 if(avccontext->cutoff > 0) { 77 cfreq = avccontext->cutoff / 1000.0; 78 if(vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)) 79 return -1; 80 } 81 82 return vorbis_encode_setup_init(vi); 83} 84 85static av_cold int oggvorbis_encode_init(AVCodecContext *avccontext) { 86 OggVorbisContext *context = avccontext->priv_data ; 87 ogg_packet header, header_comm, header_code; 88 uint8_t *p; 89 unsigned int offset, len; 90 91 vorbis_info_init(&context->vi) ; 92 if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) { 93 av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed\n") ; 94 return -1 ; 95 } 96 vorbis_analysis_init(&context->vd, &context->vi) ; 97 vorbis_block_init(&context->vd, &context->vb) ; 98 99 vorbis_comment_init(&context->vc); 100 vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT) ; 101 102 vorbis_analysis_headerout(&context->vd, &context->vc, &header, 103 &header_comm, &header_code); 104 105 len = header.bytes + header_comm.bytes + header_code.bytes; 106 avccontext->extradata_size= 64 + len + len/255; 107 p = avccontext->extradata= av_mallocz(avccontext->extradata_size); 108 p[0] = 2; 109 offset = 1; 110 offset += av_xiphlacing(&p[offset], header.bytes); 111 offset += av_xiphlacing(&p[offset], header_comm.bytes); 112 memcpy(&p[offset], header.packet, header.bytes); 113 offset += header.bytes; 114 memcpy(&p[offset], header_comm.packet, header_comm.bytes); 115 offset += header_comm.bytes; 116 memcpy(&p[offset], header_code.packet, header_code.bytes); 117 offset += header_code.bytes; 118 avccontext->extradata_size = offset; 119 avccontext->extradata= av_realloc(avccontext->extradata, avccontext->extradata_size); 120 121/* vorbis_block_clear(&context->vb); 122 vorbis_dsp_clear(&context->vd); 123 vorbis_info_clear(&context->vi);*/ 124 vorbis_comment_clear(&context->vc); 125 126 avccontext->frame_size = OGGVORBIS_FRAME_SIZE ; 127 128 avccontext->coded_frame= avcodec_alloc_frame(); 129 avccontext->coded_frame->key_frame= 1; 130 131 return 0 ; 132} 133 134 135static int oggvorbis_encode_frame(AVCodecContext *avccontext, 136 unsigned char *packets, 137 int buf_size, void *data) 138{ 139 OggVorbisContext *context = avccontext->priv_data ; 140 ogg_packet op ; 141 signed short *audio = data ; 142 int l; 143 144 if(data) { 145 int samples = OGGVORBIS_FRAME_SIZE; 146 float **buffer ; 147 148 buffer = vorbis_analysis_buffer(&context->vd, samples) ; 149 if(context->vi.channels == 1) { 150 for(l = 0 ; l < samples ; l++) 151 buffer[0][l]=audio[l]/32768.f; 152 } else { 153 for(l = 0 ; l < samples ; l++){ 154 buffer[0][l]=audio[l*2]/32768.f; 155 buffer[1][l]=audio[l*2+1]/32768.f; 156 } 157 } 158 vorbis_analysis_wrote(&context->vd, samples) ; 159 } else { 160 if(!context->eof) 161 vorbis_analysis_wrote(&context->vd, 0) ; 162 context->eof = 1; 163 } 164 165 while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) { 166 vorbis_analysis(&context->vb, NULL); 167 vorbis_bitrate_addblock(&context->vb) ; 168 169 while(vorbis_bitrate_flushpacket(&context->vd, &op)) { 170 /* i'd love to say the following line is a hack, but sadly it's 171 * not, apparently the end of stream decision is in libogg. */ 172 if(op.bytes==1) 173 continue; 174 memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet)); 175 context->buffer_index += sizeof(ogg_packet); 176 memcpy(context->buffer + context->buffer_index, op.packet, op.bytes); 177 context->buffer_index += op.bytes; 178// av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes); 179 } 180 } 181 182 l=0; 183 if(context->buffer_index){ 184 ogg_packet *op2= (ogg_packet*)context->buffer; 185 op2->packet = context->buffer + sizeof(ogg_packet); 186 187 l= op2->bytes; 188 avccontext->coded_frame->pts= av_rescale_q(op2->granulepos, (AVRational){1, avccontext->sample_rate}, avccontext->time_base); 189 //FIXME we should reorder the user supplied pts and not assume that they are spaced by 1/sample_rate 190 191 memcpy(packets, op2->packet, l); 192 context->buffer_index -= l + sizeof(ogg_packet); 193 memcpy(context->buffer, context->buffer + l + sizeof(ogg_packet), context->buffer_index); 194// av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l); 195 } 196 197 return l; 198} 199 200 201static av_cold int oggvorbis_encode_close(AVCodecContext *avccontext) { 202 OggVorbisContext *context = avccontext->priv_data ; 203/* ogg_packet op ; */ 204 205 vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */ 206 207 vorbis_block_clear(&context->vb); 208 vorbis_dsp_clear(&context->vd); 209 vorbis_info_clear(&context->vi); 210 211 av_freep(&avccontext->coded_frame); 212 av_freep(&avccontext->extradata); 213 214 return 0 ; 215} 216 217 218AVCodec libvorbis_encoder = { 219 "libvorbis", 220 AVMEDIA_TYPE_AUDIO, 221 CODEC_ID_VORBIS, 222 sizeof(OggVorbisContext), 223 oggvorbis_encode_init, 224 oggvorbis_encode_frame, 225 oggvorbis_encode_close, 226 .capabilities= CODEC_CAP_DELAY, 227 .sample_fmts = (const enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, 228 .long_name= NULL_IF_CONFIG_SMALL("libvorbis Vorbis"), 229} ; 230