Statistics
| Branch: | Revision:

ffmpeg / libavcodec / oggvorbis.c @ 08f7073a

History | View | Annotate | Download (8.82 KB)

1
/**
2
 * @file oggvorbis.c
3
 * Ogg Vorbis codec support via libvorbisenc.
4
 * @author Mark Hills <mark@pogo.org.uk>
5
 */
6

    
7
#include <vorbis/vorbisenc.h>
8

    
9
#include "avcodec.h"
10

    
11
#undef NDEBUG
12
#include <assert.h>
13

    
14
#define OGGVORBIS_FRAME_SIZE 64
15

    
16
#define BUFFER_SIZE (1024*64)
17

    
18
typedef struct OggVorbisContext {
19
    vorbis_info vi ;
20
    vorbis_dsp_state vd ;
21
    vorbis_block vb ;
22
    uint8_t buffer[BUFFER_SIZE];
23
    int buffer_index;
24
    int64_t fake_pts; //pts which libavformat will guess, HACK FIXME
25

    
26
    /* decoder */
27
    vorbis_comment vc ;
28
    ogg_packet op;
29
} OggVorbisContext ;
30

    
31

    
32
static int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
33

    
34
#ifdef OGGVORBIS_VBR_BY_ESTIMATE
35
    /* variable bitrate by estimate */
36

    
37
    return (vorbis_encode_setup_managed(vi, avccontext->channels,
38
              avccontext->sample_rate, -1, avccontext->bit_rate, -1) ||
39
            vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL) ||
40
            vorbis_encode_setup_init(vi)) ;
41
#else
42
    /* constant bitrate */
43

    
44
    return vorbis_encode_init(vi, avccontext->channels,
45
                  avccontext->sample_rate, -1, avccontext->bit_rate, -1) ;
46
#endif
47
}
48

    
49
static int oggvorbis_encode_init(AVCodecContext *avccontext) {
50
    OggVorbisContext *context = avccontext->priv_data ;
51
    ogg_packet header, header_comm, header_code;
52
    uint8_t *p;
53

    
54
    vorbis_info_init(&context->vi) ;
55
    if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
56
        av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed") ;
57
        return -1 ;
58
    }
59
    vorbis_analysis_init(&context->vd, &context->vi) ;
60
    vorbis_block_init(&context->vd, &context->vb) ;
61

    
62
    vorbis_comment_init(&context->vc);
63
    vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT) ;
64

    
65
    vorbis_analysis_headerout(&context->vd, &context->vc, &header,
66
                                &header_comm, &header_code);
67
    
68
    avccontext->extradata_size= 3*2 + header.bytes + header_comm.bytes +  header_code.bytes;
69
    p= avccontext->extradata= av_mallocz(avccontext->extradata_size);
70
    
71
    *(p++) = header.bytes>>8;
72
    *(p++) = header.bytes&0xFF;
73
    memcpy(p, header.packet, header.bytes);
74
    p += header.bytes;
75
    
76
    *(p++) = header_comm.bytes>>8;
77
    *(p++) = header_comm.bytes&0xFF;
78
    memcpy(p, header_comm.packet, header_comm.bytes);
79
    p += header_comm.bytes;
80
    
81
    *(p++) = header_code.bytes>>8;
82
    *(p++) = header_code.bytes&0xFF;
83
    memcpy(p, header_code.packet, header_code.bytes);
84
                                
85
/*    vorbis_block_clear(&context->vb);
86
    vorbis_dsp_clear(&context->vd);
87
    vorbis_info_clear(&context->vi);*/
88
    vorbis_comment_clear(&context->vc);
89
       
90
    avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
91
 
92
    avccontext->coded_frame= avcodec_alloc_frame();
93
    avccontext->coded_frame->key_frame= 1;
94
    
95
    return 0 ;
96
}
97

    
98

    
99
static int oggvorbis_encode_frame(AVCodecContext *avccontext,
100
                                  unsigned char *packets,
101
                           int buf_size, void *data)
102
{
103
    OggVorbisContext *context = avccontext->priv_data ;
104
    float **buffer ;
105
    ogg_packet op ;
106
    signed char *audio = data ;
107
    int l, samples = OGGVORBIS_FRAME_SIZE ;
108

    
109
    buffer = vorbis_analysis_buffer(&context->vd, samples) ;
110

    
111
    if(context->vi.channels == 1) {
112
        for(l = 0 ; l < samples ; l++)
113
            buffer[0][l]=((audio[l*2+1]<<8)|(0x00ff&(int)audio[l*2]))/32768.f;
114
    } else {
115
        for(l = 0 ; l < samples ; l++){
116
            buffer[0][l]=((audio[l*4+1]<<8)|(0x00ff&(int)audio[l*4]))/32768.f;
117
            buffer[1][l]=((audio[l*4+3]<<8)|(0x00ff&(int)audio[l*4+2]))/32768.f;
118
        }
119
    }
120
    
121
    vorbis_analysis_wrote(&context->vd, samples) ; 
122

    
123
    while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
124
        vorbis_analysis(&context->vb, NULL);
125
        vorbis_bitrate_addblock(&context->vb) ;
126

    
127
        while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
128
            memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet));
129
            context->buffer_index += sizeof(ogg_packet);
130
            memcpy(context->buffer + context->buffer_index, op.packet, op.bytes);
131
            context->buffer_index += op.bytes;
132
//            av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes);
133
        }
134
    }
135

    
136
    l=0;
137
    if(context->buffer_index){
138
        ogg_packet *op2= (ogg_packet*)context->buffer;
139
        op2->packet = context->buffer + sizeof(ogg_packet);
140

    
141
        if(op2->granulepos <= context->fake_pts /*&& (context->fake_pts || context->buffer_index > 4*1024)*/){
142
            assert(op2->granulepos == context->fake_pts);
143
            l=  op2->bytes;
144

    
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
        }
149
//        av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l);
150
    }
151

    
152
    if(l || context->fake_pts){
153
        context->fake_pts += avccontext->frame_size;
154
    }
155
        
156
    return l;
157
}
158

    
159

    
160
static int oggvorbis_encode_close(AVCodecContext *avccontext) {
161
    OggVorbisContext *context = avccontext->priv_data ;
162
/*  ogg_packet op ; */
163
    
164
    vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */
165

    
166
    /* We need to write all the remaining packets into the stream
167
     * on closing */
168
    
169
    av_log(avccontext, AV_LOG_ERROR, "fixme: not all packets written on oggvorbis_encode_close()\n") ;
170

    
171
/*
172
    while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
173
        memcpy(packets + l, &op, sizeof(ogg_packet)) ;
174
        memcpy(packets + l + sizeof(ogg_packet), op.packet, op.bytes) ;
175
        l += sizeof(ogg_packet) + op.bytes ;        
176
    }
177
*/
178

    
179
    vorbis_block_clear(&context->vb);
180
    vorbis_dsp_clear(&context->vd);
181
    vorbis_info_clear(&context->vi);
182

    
183
    av_freep(&avccontext->coded_frame);
184
    av_freep(&avccontext->extradata);
185
  
186
    return 0 ;
187
}
188

    
189

    
190
AVCodec oggvorbis_encoder = {
191
    "vorbis",
192
    CODEC_TYPE_AUDIO,
193
    CODEC_ID_VORBIS,
194
    sizeof(OggVorbisContext),
195
    oggvorbis_encode_init,
196
    oggvorbis_encode_frame,
197
    oggvorbis_encode_close
198
} ;
199

    
200

    
201
static int oggvorbis_decode_init(AVCodecContext *avccontext) {
202
    OggVorbisContext *context = avccontext->priv_data ;
203
    uint8_t *p= avccontext->extradata;
204
    int i;
205

    
206
    vorbis_info_init(&context->vi) ;
207
    vorbis_comment_init(&context->vc) ;
208

    
209
    for(i=0; i<3; i++){
210
        context->op.b_o_s= i==0;
211
        context->op.bytes= *(p++)<<8;
212
        context->op.bytes+=*(p++);
213
        context->op.packet= p;
214
        p += context->op.bytes;
215

    
216
        if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){
217
            av_log(avccontext, AV_LOG_ERROR, "%d. vorbis header damaged\n", i+1);
218
            return -1;
219
        }
220
    }
221
    avccontext->channels = context->vi.channels;
222
    avccontext->sample_rate = context->vi.rate;
223

    
224
    vorbis_synthesis_init(&context->vd, &context->vi);
225
    vorbis_block_init(&context->vd, &context->vb); 
226

    
227
    return 0 ;
228
}
229

    
230

    
231
static inline int conv(int samples, float **pcm, char *buf, int channels) {
232
    int i, j, val ;
233
    ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ;
234
    float *mono ;
235
 
236
    for(i = 0 ; i < channels ; i++){
237
        ptr = &data[i];
238
        mono = pcm[i] ;
239
        
240
        for(j = 0 ; j < samples ; j++) {
241
            
242
            val = mono[j] * 32767.f;
243
            
244
            if(val > 32767) val = 32767 ;
245
            if(val < -32768) val = -32768 ;
246
                       
247
            *ptr = val ;
248
            ptr += channels;
249
        }
250
    }
251
    
252
    return 0 ;
253
}
254
           
255
        
256
static int oggvorbis_decode_frame(AVCodecContext *avccontext,
257
                        void *data, int *data_size,
258
                        uint8_t *buf, int buf_size)
259
{
260
    OggVorbisContext *context = avccontext->priv_data ;
261
    float **pcm ;
262
    ogg_packet *op= &context->op;    
263
    int samples, total_samples, total_bytes,i;
264
 
265
    if(!buf_size){
266
    //FIXME flush
267
        return 0;
268
    }
269
    
270
    op->packet = buf;
271
    op->bytes  = buf_size;
272

    
273
//    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);
274
    
275
/*    for(i=0; i<op->bytes; i++)
276
      av_log(avccontext, AV_LOG_DEBUG, "%02X ", op->packet[i]);
277
    av_log(avccontext, AV_LOG_DEBUG, "\n");*/
278

    
279
    if(vorbis_synthesis(&context->vb, op) == 0)
280
        vorbis_synthesis_blockin(&context->vd, &context->vb) ;
281
    
282
    total_samples = 0 ;
283
    total_bytes = 0 ;
284

    
285
    while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) {
286
        conv(samples, pcm, (char*)data + total_bytes, context->vi.channels) ;
287
        total_bytes += samples * 2 * context->vi.channels ;
288
        total_samples += samples ;
289
        vorbis_synthesis_read(&context->vd, samples) ;
290
    }
291

    
292
    *data_size = total_bytes ;   
293
    return buf_size ;
294
}
295

    
296

    
297
static int oggvorbis_decode_close(AVCodecContext *avccontext) {
298
    OggVorbisContext *context = avccontext->priv_data ;
299
   
300
    vorbis_info_clear(&context->vi) ;
301
    vorbis_comment_clear(&context->vc) ;
302

    
303
    return 0 ;
304
}
305

    
306

    
307
AVCodec oggvorbis_decoder = {
308
    "vorbis",
309
    CODEC_TYPE_AUDIO,
310
    CODEC_ID_VORBIS,
311
    sizeof(OggVorbisContext),
312
    oggvorbis_decode_init,
313
    NULL,
314
    oggvorbis_decode_close,
315
    oggvorbis_decode_frame,
316
} ;