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