Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_04 / synfig-core / src / modules / mod_libavcodec / libavcodec / oggvorbis.c
1 /**
2  * @file oggvorbis.c
3  * Ogg Vorbis codec support via libvorbisenc.
4  * @author Mark Hills <mark@pogo.org.uk>
5  */
6
7 #include <time.h>
8
9 #include <vorbis/vorbisenc.h>
10
11 #include "avcodec.h"
12 #include "oggvorbis.h"
13
14 #define OGGVORBIS_FRAME_SIZE 1024
15
16
17 typedef struct OggVorbisContext {
18     vorbis_info vi ;
19     vorbis_dsp_state vd ;
20     vorbis_block vb ;
21
22     /* decoder */
23     vorbis_comment vc ;
24 } OggVorbisContext ;
25
26
27 int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
28
29 #ifdef OGGVORBIS_VBR_BY_ESTIMATE
30     /* variable bitrate by estimate */
31
32     return (vorbis_encode_setup_managed(vi, avccontext->channels,
33               avccontext->sample_rate, -1, avccontext->bit_rate, -1) ||
34             vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL) ||
35             vorbis_encode_setup_init(vi)) ;
36 #else
37     /* constant bitrate */
38
39     return vorbis_encode_init(vi, avccontext->channels,
40                   avccontext->sample_rate, -1, avccontext->bit_rate, -1) ;
41 #endif
42 }
43
44
45 static int oggvorbis_encode_init(AVCodecContext *avccontext) {
46     OggVorbisContext *context = avccontext->priv_data ;
47
48     vorbis_info_init(&context->vi) ;
49     if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
50         fprintf(stderr, "oggvorbis_encode_init: init_encoder failed") ;
51         return -1 ;
52     }
53     vorbis_analysis_init(&context->vd, &context->vi) ;
54     vorbis_block_init(&context->vd, &context->vb) ;
55
56     avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
57  
58     avccontext->coded_frame= avcodec_alloc_frame();
59     avccontext->coded_frame->key_frame= 1;
60     
61     return 0 ;
62 }
63
64
65 static int oggvorbis_encode_frame(AVCodecContext *avccontext,
66                                   unsigned char *packets,
67                            int buf_size, void *data)
68 {
69     OggVorbisContext *context = avccontext->priv_data ;
70     float **buffer ;
71     ogg_packet op ;
72     signed char *audio = data ;
73     int l, samples = OGGVORBIS_FRAME_SIZE ;
74
75     buffer = vorbis_analysis_buffer(&context->vd, samples) ;
76
77     if(context->vi.channels == 1) {
78         for(l = 0 ; l < samples ; l++)
79             buffer[0][l]=((audio[l*2+1]<<8)|(0x00ff&(int)audio[l*2]))/32768.f;
80     } else {
81         for(l = 0 ; l < samples ; l++){
82             buffer[0][l]=((audio[l*4+1]<<8)|(0x00ff&(int)audio[l*4]))/32768.f;
83             buffer[1][l]=((audio[l*4+3]<<8)|(0x00ff&(int)audio[l*4+2]))/32768.f;
84         }
85     }
86     
87     vorbis_analysis_wrote(&context->vd, samples) ; 
88
89     l = 0 ;
90
91     while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
92         vorbis_analysis(&context->vb, NULL);
93         vorbis_bitrate_addblock(&context->vb) ;
94
95         while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
96             memcpy(packets + l, &op, sizeof(ogg_packet)) ;
97             memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
98             l += sizeof(ogg_packet) + op.bytes ;
99         }
100     }
101
102     return l ;
103 }
104
105
106 static int oggvorbis_encode_close(AVCodecContext *avccontext) {
107     OggVorbisContext *context = avccontext->priv_data ;
108 /*  ogg_packet op ; */
109     
110     vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
111
112     /* We need to write all the remaining packets into the stream
113      * on closing */
114     
115     fprintf(stderr, "fixme: not all packets written on oggvorbis_encode_close()\n") ;
116
117 /*
118     while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
119         memcpy(packets + l, &op, sizeof(ogg_packet)) ;
120         memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
121         l += sizeof(ogg_packet) + op.bytes ;    
122     }
123 */
124
125     vorbis_block_clear(&context->vb);
126     vorbis_dsp_clear(&context->vd);
127     vorbis_info_clear(&context->vi);
128
129     av_freep(&avccontext->coded_frame);
130   
131     return 0 ;
132 }
133
134
135 AVCodec oggvorbis_encoder = {
136     "vorbis",
137     CODEC_TYPE_AUDIO,
138     CODEC_ID_VORBIS,
139     sizeof(OggVorbisContext),
140     oggvorbis_encode_init,
141     oggvorbis_encode_frame,
142     oggvorbis_encode_close
143 } ;
144
145
146 static int oggvorbis_decode_init(AVCodecContext *avccontext) {
147     OggVorbisContext *context = avccontext->priv_data ;
148
149     vorbis_info_init(&context->vi) ;
150     vorbis_comment_init(&context->vc) ;
151
152     return 0 ;
153 }
154
155
156 static inline int conv(int samples, float **pcm, char *buf, int channels) {
157     int i, j, val ;
158     ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ;
159     float *mono ;
160  
161     for(i = 0 ; i < channels ; i++){
162         ptr = &data[i];
163         mono = pcm[i] ;
164         
165         for(j = 0 ; j < samples ; j++) {
166             
167             val = mono[j] * 32767.f;
168             
169             if(val > 32767) val = 32767 ;
170             if(val < -32768) val = -32768 ;
171                     
172             *ptr = val ;
173             ptr += channels;
174         }
175     }
176     
177     return 0 ;
178 }
179            
180         
181 static int oggvorbis_decode_frame(AVCodecContext *avccontext,
182                         void *data, int *data_size,
183                         uint8_t *buf, int buf_size)
184 {
185     OggVorbisContext *context = avccontext->priv_data ;
186     ogg_packet *op = (ogg_packet*)buf ;
187     float **pcm ;
188     int samples, total_samples, total_bytes ;
189  
190     op->packet = (char*)op + sizeof(ogg_packet) ; /* correct data pointer */
191
192     if(op->packetno < 3) {
193         vorbis_synthesis_headerin(&context->vi, &context->vc, op) ;
194         return buf_size ;
195     }
196
197     if(op->packetno == 3) {
198         fprintf(stderr, "vorbis_decode: %d channel, %ldHz, encoder `%s'\n",
199                 context->vi.channels, context->vi.rate, context->vc.vendor);
200
201         avccontext->channels = context->vi.channels ;
202         avccontext->sample_rate = context->vi.rate ;
203         
204         vorbis_synthesis_init(&context->vd, &context->vi) ;
205         vorbis_block_init(&context->vd, &context->vb); 
206     }
207
208     if(vorbis_synthesis(&context->vb, op) == 0)
209         vorbis_synthesis_blockin(&context->vd, &context->vb) ;
210     
211     total_samples = 0 ;
212     total_bytes = 0 ;
213
214     while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) {
215         conv(samples, pcm, (char*)data + total_bytes, context->vi.channels) ;
216         total_bytes += samples * 2 * context->vi.channels ;
217         total_samples += samples ;
218         vorbis_synthesis_read(&context->vd, samples) ;
219     }
220
221     *data_size = total_bytes ;   
222     return buf_size ;
223 }
224
225
226 static int oggvorbis_decode_close(AVCodecContext *avccontext) {
227     OggVorbisContext *context = avccontext->priv_data ;
228    
229     vorbis_info_clear(&context->vi) ;
230     vorbis_comment_clear(&context->vc) ;
231
232     return 0 ;
233 }
234
235
236 AVCodec oggvorbis_decoder = {
237     "vorbis",
238     CODEC_TYPE_AUDIO,
239     CODEC_ID_VORBIS,
240     sizeof(OggVorbisContext),
241     oggvorbis_decode_init,
242     NULL,
243     oggvorbis_decode_close,
244     oggvorbis_decode_frame,
245 } ;