3 * Ogg Vorbis codec support via libvorbisenc.
4 * @author Mark Hills <mark@pogo.org.uk>
7 #include <vorbis/vorbisenc.h>
14 #define OGGVORBIS_FRAME_SIZE 64
16 #define BUFFER_SIZE (1024*64)
18 typedef struct OggVorbisContext {
22 uint8_t buffer[BUFFER_SIZE];
31 static int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
33 #ifdef OGGVORBIS_VBR_BY_ESTIMATE
34 /* variable bitrate by estimate */
36 return (vorbis_encode_setup_managed(vi, avccontext->channels,
37 avccontext->sample_rate, -1, avccontext->bit_rate, -1) ||
38 vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL) ||
39 vorbis_encode_setup_init(vi)) ;
41 /* constant bitrate */
43 return vorbis_encode_init(vi, avccontext->channels,
44 avccontext->sample_rate, -1, avccontext->bit_rate, -1) ;
48 static int oggvorbis_encode_init(AVCodecContext *avccontext) {
49 OggVorbisContext *context = avccontext->priv_data ;
50 ogg_packet header, header_comm, header_code;
53 vorbis_info_init(&context->vi) ;
54 if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
55 av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed") ;
58 vorbis_analysis_init(&context->vd, &context->vi) ;
59 vorbis_block_init(&context->vd, &context->vb) ;
61 vorbis_comment_init(&context->vc);
62 vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT) ;
64 vorbis_analysis_headerout(&context->vd, &context->vc, &header,
65 &header_comm, &header_code);
67 avccontext->extradata_size= 3*2 + header.bytes + header_comm.bytes + header_code.bytes;
68 p= avccontext->extradata= av_mallocz(avccontext->extradata_size);
70 *(p++) = header.bytes>>8;
71 *(p++) = header.bytes&0xFF;
72 memcpy(p, header.packet, header.bytes);
75 *(p++) = header_comm.bytes>>8;
76 *(p++) = header_comm.bytes&0xFF;
77 memcpy(p, header_comm.packet, header_comm.bytes);
78 p += header_comm.bytes;
80 *(p++) = header_code.bytes>>8;
81 *(p++) = header_code.bytes&0xFF;
82 memcpy(p, header_code.packet, header_code.bytes);
84 /* vorbis_block_clear(&context->vb);
85 vorbis_dsp_clear(&context->vd);
86 vorbis_info_clear(&context->vi);*/
87 vorbis_comment_clear(&context->vc);
89 avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
91 avccontext->coded_frame= avcodec_alloc_frame();
92 avccontext->coded_frame->key_frame= 1;
98 static int oggvorbis_encode_frame(AVCodecContext *avccontext,
99 unsigned char *packets,
100 int buf_size, void *data)
102 OggVorbisContext *context = avccontext->priv_data ;
105 signed char *audio = data ;
106 int l, samples = data ? OGGVORBIS_FRAME_SIZE : 0;
108 buffer = vorbis_analysis_buffer(&context->vd, samples) ;
110 if(context->vi.channels == 1) {
111 for(l = 0 ; l < samples ; l++)
112 buffer[0][l]=((audio[l*2+1]<<8)|(0x00ff&(int)audio[l*2]))/32768.f;
114 for(l = 0 ; l < samples ; l++){
115 buffer[0][l]=((audio[l*4+1]<<8)|(0x00ff&(int)audio[l*4]))/32768.f;
116 buffer[1][l]=((audio[l*4+3]<<8)|(0x00ff&(int)audio[l*4+2]))/32768.f;
120 vorbis_analysis_wrote(&context->vd, samples) ;
122 while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
123 vorbis_analysis(&context->vb, NULL);
124 vorbis_bitrate_addblock(&context->vb) ;
126 while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
127 if(op.bytes==1) //id love to say this is a hack, bad sadly its not, appearently the end of stream decission is in libogg
129 memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet));
130 context->buffer_index += sizeof(ogg_packet);
131 memcpy(context->buffer + context->buffer_index, op.packet, op.bytes);
132 context->buffer_index += op.bytes;
133 // av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes);
138 if(context->buffer_index){
139 ogg_packet *op2= (ogg_packet*)context->buffer;
140 op2->packet = context->buffer + sizeof(ogg_packet);
143 avccontext->coded_frame->pts= av_rescale(op2->granulepos, AV_TIME_BASE, avccontext->sample_rate);
145 memcpy(packets, op2->packet, l);
146 context->buffer_index -= l + sizeof(ogg_packet);
147 memcpy(context->buffer, context->buffer + l + sizeof(ogg_packet), context->buffer_index);
148 // av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l);
155 static int oggvorbis_encode_close(AVCodecContext *avccontext) {
156 OggVorbisContext *context = avccontext->priv_data ;
157 /* ogg_packet op ; */
159 vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
161 vorbis_block_clear(&context->vb);
162 vorbis_dsp_clear(&context->vd);
163 vorbis_info_clear(&context->vi);
165 av_freep(&avccontext->coded_frame);
166 av_freep(&avccontext->extradata);
172 AVCodec oggvorbis_encoder = {
176 sizeof(OggVorbisContext),
177 oggvorbis_encode_init,
178 oggvorbis_encode_frame,
179 oggvorbis_encode_close,
180 .capabilities= CODEC_CAP_DELAY,
184 static int oggvorbis_decode_init(AVCodecContext *avccontext) {
185 OggVorbisContext *context = avccontext->priv_data ;
186 uint8_t *p= avccontext->extradata;
189 vorbis_info_init(&context->vi) ;
190 vorbis_comment_init(&context->vc) ;
193 context->op.b_o_s= i==0;
194 context->op.bytes= *(p++)<<8;
195 context->op.bytes+=*(p++);
196 context->op.packet= p;
197 p += context->op.bytes;
199 if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){
200 av_log(avccontext, AV_LOG_ERROR, "%d. vorbis header damaged\n", i+1);
204 avccontext->channels = context->vi.channels;
205 avccontext->sample_rate = context->vi.rate;
207 vorbis_synthesis_init(&context->vd, &context->vi);
208 vorbis_block_init(&context->vd, &context->vb);
214 static inline int conv(int samples, float **pcm, char *buf, int channels) {
216 ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ;
219 for(i = 0 ; i < channels ; i++){
223 for(j = 0 ; j < samples ; j++) {
225 val = mono[j] * 32767.f;
227 if(val > 32767) val = 32767 ;
228 if(val < -32768) val = -32768 ;
239 static int oggvorbis_decode_frame(AVCodecContext *avccontext,
240 void *data, int *data_size,
241 uint8_t *buf, int buf_size)
243 OggVorbisContext *context = avccontext->priv_data ;
245 ogg_packet *op= &context->op;
246 int samples, total_samples, total_bytes,i;
254 op->bytes = buf_size;
256 // av_log(avccontext, AV_LOG_DEBUG, "%d %d %d %lld %lld %d %d\n", op->bytes, op->b_o_s, op->e_o_s, op->granulepos, op->packetno, buf_size, context->vi.rate);
258 /* for(i=0; i<op->bytes; i++)
259 av_log(avccontext, AV_LOG_DEBUG, "%02X ", op->packet[i]);
260 av_log(avccontext, AV_LOG_DEBUG, "\n");*/
262 if(vorbis_synthesis(&context->vb, op) == 0)
263 vorbis_synthesis_blockin(&context->vd, &context->vb) ;
268 while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) {
269 conv(samples, pcm, (char*)data + total_bytes, context->vi.channels) ;
270 total_bytes += samples * 2 * context->vi.channels ;
271 total_samples += samples ;
272 vorbis_synthesis_read(&context->vd, samples) ;
275 *data_size = total_bytes ;
280 static int oggvorbis_decode_close(AVCodecContext *avccontext) {
281 OggVorbisContext *context = avccontext->priv_data ;
283 vorbis_info_clear(&context->vi) ;
284 vorbis_comment_clear(&context->vc) ;
290 AVCodec oggvorbis_decoder = {
294 sizeof(OggVorbisContext),
295 oggvorbis_decode_init,
297 oggvorbis_decode_close,
298 oggvorbis_decode_frame,
299 .capabilities= CODEC_CAP_DELAY,