libvorbis.c 6.97 KB
Newer Older
1 2 3
/*
 * copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
 *
4 5 6
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
 * 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 13 14 15 16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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
 */

Michael Niedermayer's avatar
Michael Niedermayer committed
21 22 23 24
/**
 * @file oggvorbis.c
 * Ogg Vorbis codec support via libvorbisenc.
 * @author Mark Hills <mark@pogo.org.uk>
25 26 27 28 29
 */

#include <vorbis/vorbisenc.h>

#include "avcodec.h"
30
#include "bytestream.h"
31

32 33 34
#undef NDEBUG
#include <assert.h>

35
#define OGGVORBIS_FRAME_SIZE 64
36

37
#define BUFFER_SIZE (1024*64)
38 39 40 41 42

typedef struct OggVorbisContext {
    vorbis_info vi ;
    vorbis_dsp_state vd ;
    vorbis_block vb ;
43 44
    uint8_t buffer[BUFFER_SIZE];
    int buffer_index;
45 46 47

    /* decoder */
    vorbis_comment vc ;
48
    ogg_packet op;
49 50 51
} OggVorbisContext ;


52
static int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) {
53
    double cfreq;
54

55
    if(avccontext->flags & CODEC_FLAG_QSCALE) {
56 57
        /* variable bitrate */
        if(vorbis_encode_setup_vbr(vi, avccontext->channels,
58
                avccontext->sample_rate,
59 60 61 62 63 64 65 66
                avccontext->global_quality / (float)FF_QP2LAMBDA))
            return -1;
    } else {
        /* constant bitrate */
        if(vorbis_encode_setup_managed(vi, avccontext->channels,
                avccontext->sample_rate, -1, avccontext->bit_rate, -1))
            return -1;

67
#ifdef OGGVORBIS_VBR_BY_ESTIMATE
68 69 70 71 72
        /* variable bitrate by estimate */
        if(vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL))
            return -1;
#endif
    }
73

74 75 76 77 78 79
    /* cutoff frequency */
    if(avccontext->cutoff > 0) {
        cfreq = avccontext->cutoff / 1000.0;
        if(vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq))
            return -1;
    }
80

81
    return vorbis_encode_setup_init(vi);
82 83 84 85
}

static int oggvorbis_encode_init(AVCodecContext *avccontext) {
    OggVorbisContext *context = avccontext->priv_data ;
86 87
    ogg_packet header, header_comm, header_code;
    uint8_t *p;
88
    unsigned int offset, len;
89 90 91

    vorbis_info_init(&context->vi) ;
    if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) {
92 93
        av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed") ;
        return -1 ;
94 95 96 97
    }
    vorbis_analysis_init(&context->vd, &context->vi) ;
    vorbis_block_init(&context->vd, &context->vb) ;

98 99 100 101 102
    vorbis_comment_init(&context->vc);
    vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT) ;

    vorbis_analysis_headerout(&context->vd, &context->vc, &header,
                                &header_comm, &header_code);
103

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    len = header.bytes + header_comm.bytes +  header_code.bytes;
    avccontext->extradata_size= 64 + len + len/255;
    p = avccontext->extradata= av_mallocz(avccontext->extradata_size);
    p[0] = 2;
    offset = 1;
    offset += av_xiphlacing(&p[offset], header.bytes);
    offset += av_xiphlacing(&p[offset], header_comm.bytes);
    memcpy(&p[offset], header.packet, header.bytes);
    offset += header.bytes;
    memcpy(&p[offset], header_comm.packet, header_comm.bytes);
    offset += header_comm.bytes;
    memcpy(&p[offset], header_code.packet, header_code.bytes);
    offset += header_code.bytes;
    avccontext->extradata_size = offset;
    avccontext->extradata= av_realloc(avccontext->extradata, avccontext->extradata_size);
119

120 121 122 123
/*    vorbis_block_clear(&context->vb);
    vorbis_dsp_clear(&context->vd);
    vorbis_info_clear(&context->vi);*/
    vorbis_comment_clear(&context->vc);
124

125
    avccontext->frame_size = OGGVORBIS_FRAME_SIZE ;
126

127 128
    avccontext->coded_frame= avcodec_alloc_frame();
    avccontext->coded_frame->key_frame= 1;
129

130 131 132 133
    return 0 ;
}


134
static int oggvorbis_encode_frame(AVCodecContext *avccontext,
135 136
                                  unsigned char *packets,
                           int buf_size, void *data)
137 138 139 140
{
    OggVorbisContext *context = avccontext->priv_data ;
    float **buffer ;
    ogg_packet op ;
141
    signed short *audio = data ;
142
    int l, samples = data ? OGGVORBIS_FRAME_SIZE : 0;
143 144 145 146

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

    if(context->vi.channels == 1) {
147 148
        for(l = 0 ; l < samples ; l++)
            buffer[0][l]=audio[l]/32768.f;
149
    } else {
150 151 152 153
        for(l = 0 ; l < samples ; l++){
            buffer[0][l]=audio[l*2]/32768.f;
            buffer[1][l]=audio[l*2+1]/32768.f;
        }
154
    }
155 156

    vorbis_analysis_wrote(&context->vd, samples) ;
157 158

    while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
159 160
        vorbis_analysis(&context->vb, NULL);
        vorbis_bitrate_addblock(&context->vb) ;
161

162
        while(vorbis_bitrate_flushpacket(&context->vd, &op)) {
163 164 165
            /* i'd love to say the following line is a hack, but sadly it's
             * not, apparently the end of stream decision is in libogg. */
            if(op.bytes==1)
166
                continue;
167 168 169 170 171
            memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet));
            context->buffer_index += sizeof(ogg_packet);
            memcpy(context->buffer + context->buffer_index, op.packet, op.bytes);
            context->buffer_index += op.bytes;
//            av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes);
172
        }
173 174
    }

175
    l=0;
176
    if(context->buffer_index){
177
        ogg_packet *op2= (ogg_packet*)context->buffer;
178
        op2->packet = context->buffer + sizeof(ogg_packet);
179

180
        l=  op2->bytes;
181
        avccontext->coded_frame->pts= av_rescale_q(op2->granulepos, (AVRational){1, avccontext->sample_rate}, avccontext->time_base);
Michael Niedermayer's avatar
Michael Niedermayer committed
182
        //FIXME we should reorder the user supplied pts and not assume that they are spaced by 1/sample_rate
183

184 185 186
        memcpy(packets, op2->packet, l);
        context->buffer_index -= l + sizeof(ogg_packet);
        memcpy(context->buffer, context->buffer + l + sizeof(ogg_packet), context->buffer_index);
187 188 189
//        av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l);
    }

190
    return l;
191 192 193
}


194
static int oggvorbis_encode_close(AVCodecContext *avccontext) {
195 196
    OggVorbisContext *context = avccontext->priv_data ;
/*  ogg_packet op ; */
197

198 199 200 201 202
    vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */

    vorbis_block_clear(&context->vb);
    vorbis_dsp_clear(&context->vd);
    vorbis_info_clear(&context->vi);
203 204

    av_freep(&avccontext->coded_frame);
205
    av_freep(&avccontext->extradata);
206

207 208 209 210
    return 0 ;
}


211 212
AVCodec libvorbis_encoder = {
    "libvorbis",
213 214 215 216 217
    CODEC_TYPE_AUDIO,
    CODEC_ID_VORBIS,
    sizeof(OggVorbisContext),
    oggvorbis_encode_init,
    oggvorbis_encode_frame,
218 219
    oggvorbis_encode_close,
    .capabilities= CODEC_CAP_DELAY,
220
} ;