oggvorbis support patch by (Mark Hills <mark at pogo dot org dot uk>)
[ffmpeg.git] / libavcodec / oggvorbis.c
1 /*
2  * Ogg Vorbis codec support via libvorbisenc
3  * Mark Hills <mark@pogo.org.uk>
4  */
5
6 #include <time.h>
7
8 #include <vorbis/vorbisenc.h>
9
10 #include "avcodec.h"
11 #include "oggvorbis.h"
12
13 #define OGGVORBIS_FRAME_SIZE 1024
14
15
16 typedef struct OggVorbisContext {
17     vorbis_info vi ;
18     vorbis_dsp_state vd ;
19     vorbis_block vb ;
20 } OggVorbisContext ;
21
22
23 int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
24     if(avccontext->quality) { /* VBR requested */
25
26         fprintf(stderr, "init_encode: channels=%d quality=%d\n", 
27                 avccontext->channels, avccontext->quality) ;
28
29         return vorbis_encode_init_vbr(vi, avccontext->channels,
30                   avccontext->sample_rate, (float)avccontext->quality / 1000) ;
31     }
32
33     fprintf(stderr, "init_encoder: channels=%d bitrate=%d tolerance=%d\n", 
34             avccontext->channels, avccontext->bit_rate,
35             avccontext->bit_rate_tolerance) ;
36
37     return vorbis_encode_init(vi, avccontext->channels,
38                   avccontext->sample_rate, -1, avccontext->bit_rate, -1) ;
39 }
40
41
42 static int oggvorbis_encode_init(AVCodecContext *avccontext) {
43     OggVorbisContext *context = avccontext->priv_data ;
44
45     fprintf(stderr, "oggvorbis_encode_init\n") ;
46
47     vorbis_info_init(&context->vi) ;
48
49     if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
50         fprintf(stderr, "oggvorbis_encode_init: init_encoder failed") ;
51         return -1 ;
52     }
53
54     vorbis_analysis_init(&context->vd, &context->vi) ;
55     vorbis_block_init(&context->vd, &context->vb) ;
56
57     avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
58     
59     return 0 ;
60 }
61
62
63 int oggvorbis_encode_frame(AVCodecContext *avccontext, unsigned char *packets,
64                            int buf_size, void *data)
65 {
66     OggVorbisContext *context = avccontext->priv_data ;
67     float **buffer ;
68     ogg_packet op ;
69     signed char *audio = data ;
70     int l, samples = buf_size / 16 ; /* samples = OGGVORBIS_FRAME_SIZE */ ;
71
72     buffer = vorbis_analysis_buffer(&context->vd, samples) ;
73
74     if(context->vi.channels == 1) {
75         for(l = 0 ; l < samples ; l++)
76             buffer[0][l]=((audio[l*2+1]<<8)|(0x00ff&(int)audio[l*2]))/32768.f;
77     } else {
78         for(l = 0 ; l < samples ; l++){
79             buffer[0][l]=((audio[l*4+1]<<8)|(0x00ff&(int)audio[l*4]))/32768.f;
80             buffer[1][l]=((audio[l*4+3]<<8)|(0x00ff&(int)audio[l*4+2]))/32768.f;
81         }
82     }
83     
84     vorbis_analysis_wrote(&context->vd, samples) ; 
85
86     l = 0 ;
87
88     while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
89         vorbis_analysis(&context->vb, NULL);
90         vorbis_bitrate_addblock(&context->vb) ;
91
92         while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
93             memcpy(packets + l, &op, sizeof(ogg_packet)) ;
94             memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
95             l += sizeof(ogg_packet) + op.bytes ;
96         }
97     }
98
99     return l ;
100 }
101
102
103 int oggvorbis_encode_close(AVCodecContext *avccontext) {
104     OggVorbisContext *context = avccontext->priv_data ;
105 /*  ogg_packet op ; */
106     
107     fprintf(stderr, "oggvorbis_encode_close\n") ;
108     
109     vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
110
111     /* We need to write all the remaining packets into the stream
112      * on closing */
113     
114 /*
115     while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
116         memcpy(packets + l, &op, sizeof(ogg_packet)) ;
117         memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
118         l += sizeof(ogg_packet) + op.bytes ;    
119     }
120 */
121
122     vorbis_block_clear(&context->vb);
123     vorbis_dsp_clear(&context->vd);
124     vorbis_info_clear(&context->vi);
125   
126     return 0 ;
127 }
128
129
130 AVCodec oggvorbis_encoder = {
131     "vorbis",
132     CODEC_TYPE_AUDIO,
133     CODEC_ID_VORBIS,
134     sizeof(OggVorbisContext),
135     oggvorbis_encode_init,
136     oggvorbis_encode_frame,
137     oggvorbis_encode_close
138 };
139
140