1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include <vorbis/vorbisenc.h>
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "avcodec.h"
24cabdff1aSopenharmony_ci#include "bytestream.h"
25cabdff1aSopenharmony_ci#include "codec_internal.h"
26cabdff1aSopenharmony_ci#include "internal.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_citypedef struct OggVorbisDecContext {
29cabdff1aSopenharmony_ci    vorbis_info vi;                     /**< vorbis_info used during init   */
30cabdff1aSopenharmony_ci    vorbis_dsp_state vd;                /**< DSP state used for analysis    */
31cabdff1aSopenharmony_ci    vorbis_block vb;                    /**< vorbis_block used for analysis */
32cabdff1aSopenharmony_ci    vorbis_comment vc;                  /**< VorbisComment info             */
33cabdff1aSopenharmony_ci    ogg_packet op;                      /**< ogg packet                     */
34cabdff1aSopenharmony_ci} OggVorbisDecContext;
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_cistatic int oggvorbis_decode_close(AVCodecContext *avccontext);
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_cistatic int oggvorbis_decode_init(AVCodecContext *avccontext) {
39cabdff1aSopenharmony_ci    OggVorbisDecContext *context = avccontext->priv_data ;
40cabdff1aSopenharmony_ci    uint8_t *p= avccontext->extradata;
41cabdff1aSopenharmony_ci    int i, hsizes[3], ret;
42cabdff1aSopenharmony_ci    unsigned char *headers[3], *extradata = avccontext->extradata;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    if(! avccontext->extradata_size || ! p) {
45cabdff1aSopenharmony_ci        av_log(avccontext, AV_LOG_ERROR, "vorbis extradata absent\n");
46cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
47cabdff1aSopenharmony_ci    }
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci    vorbis_info_init(&context->vi) ;
50cabdff1aSopenharmony_ci    vorbis_comment_init(&context->vc) ;
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci    if(p[0] == 0 && p[1] == 30) {
53cabdff1aSopenharmony_ci        int sizesum = 0;
54cabdff1aSopenharmony_ci        for(i = 0; i < 3; i++){
55cabdff1aSopenharmony_ci            hsizes[i] = bytestream_get_be16((const uint8_t **)&p);
56cabdff1aSopenharmony_ci            sizesum += 2 + hsizes[i];
57cabdff1aSopenharmony_ci            if (sizesum > avccontext->extradata_size) {
58cabdff1aSopenharmony_ci                av_log(avccontext, AV_LOG_ERROR, "vorbis extradata too small\n");
59cabdff1aSopenharmony_ci                ret = AVERROR_INVALIDDATA;
60cabdff1aSopenharmony_ci                goto error;
61cabdff1aSopenharmony_ci            }
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_ci            headers[i] = p;
64cabdff1aSopenharmony_ci            p += hsizes[i];
65cabdff1aSopenharmony_ci        }
66cabdff1aSopenharmony_ci    } else if(*p == 2) {
67cabdff1aSopenharmony_ci        unsigned int offset = 1;
68cabdff1aSopenharmony_ci        unsigned int sizesum = 1;
69cabdff1aSopenharmony_ci        p++;
70cabdff1aSopenharmony_ci        for(i=0; i<2; i++) {
71cabdff1aSopenharmony_ci            hsizes[i] = 0;
72cabdff1aSopenharmony_ci            while((*p == 0xFF) && (sizesum < avccontext->extradata_size)) {
73cabdff1aSopenharmony_ci                hsizes[i] += 0xFF;
74cabdff1aSopenharmony_ci                offset++;
75cabdff1aSopenharmony_ci                sizesum += 1 + 0xFF;
76cabdff1aSopenharmony_ci                p++;
77cabdff1aSopenharmony_ci            }
78cabdff1aSopenharmony_ci            hsizes[i] += *p;
79cabdff1aSopenharmony_ci            offset++;
80cabdff1aSopenharmony_ci            sizesum += 1 + *p;
81cabdff1aSopenharmony_ci            if(sizesum > avccontext->extradata_size) {
82cabdff1aSopenharmony_ci                av_log(avccontext, AV_LOG_ERROR,
83cabdff1aSopenharmony_ci                       "vorbis header sizes damaged\n");
84cabdff1aSopenharmony_ci                ret = AVERROR_INVALIDDATA;
85cabdff1aSopenharmony_ci                goto error;
86cabdff1aSopenharmony_ci            }
87cabdff1aSopenharmony_ci            p++;
88cabdff1aSopenharmony_ci        }
89cabdff1aSopenharmony_ci        hsizes[2] = avccontext->extradata_size - hsizes[0]-hsizes[1]-offset;
90cabdff1aSopenharmony_ci#if 0
91cabdff1aSopenharmony_ci        av_log(avccontext, AV_LOG_DEBUG,
92cabdff1aSopenharmony_ci               "vorbis header sizes: %d, %d, %d, / extradata_len is %d \n",
93cabdff1aSopenharmony_ci               hsizes[0], hsizes[1], hsizes[2], avccontext->extradata_size);
94cabdff1aSopenharmony_ci#endif
95cabdff1aSopenharmony_ci        headers[0] = extradata + offset;
96cabdff1aSopenharmony_ci        headers[1] = extradata + offset + hsizes[0];
97cabdff1aSopenharmony_ci        headers[2] = extradata + offset + hsizes[0] + hsizes[1];
98cabdff1aSopenharmony_ci    } else {
99cabdff1aSopenharmony_ci        av_log(avccontext, AV_LOG_ERROR,
100cabdff1aSopenharmony_ci               "vorbis initial header len is wrong: %d\n", *p);
101cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
102cabdff1aSopenharmony_ci        goto error;
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    for(i=0; i<3; i++){
106cabdff1aSopenharmony_ci        context->op.b_o_s= i==0;
107cabdff1aSopenharmony_ci        context->op.bytes = hsizes[i];
108cabdff1aSopenharmony_ci        context->op.packet = headers[i];
109cabdff1aSopenharmony_ci        if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){
110cabdff1aSopenharmony_ci            av_log(avccontext, AV_LOG_ERROR, "%d. vorbis header damaged\n", i+1);
111cabdff1aSopenharmony_ci            ret = AVERROR_INVALIDDATA;
112cabdff1aSopenharmony_ci            goto error;
113cabdff1aSopenharmony_ci        }
114cabdff1aSopenharmony_ci    }
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    av_channel_layout_uninit(&avccontext->ch_layout);
117cabdff1aSopenharmony_ci    avccontext->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
118cabdff1aSopenharmony_ci    avccontext->ch_layout.nb_channels = context->vi.channels;
119cabdff1aSopenharmony_ci    avccontext->sample_rate = context->vi.rate;
120cabdff1aSopenharmony_ci    avccontext->sample_fmt = AV_SAMPLE_FMT_S16;
121cabdff1aSopenharmony_ci    avccontext->time_base= (AVRational){1, avccontext->sample_rate};
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci    vorbis_synthesis_init(&context->vd, &context->vi);
124cabdff1aSopenharmony_ci    vorbis_block_init(&context->vd, &context->vb);
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci    return 0 ;
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci  error:
129cabdff1aSopenharmony_ci    oggvorbis_decode_close(avccontext);
130cabdff1aSopenharmony_ci    return ret;
131cabdff1aSopenharmony_ci}
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_cistatic inline int conv(int samples, float **pcm, char *buf, int channels) {
135cabdff1aSopenharmony_ci    int i, j;
136cabdff1aSopenharmony_ci    ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ;
137cabdff1aSopenharmony_ci    float *mono ;
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    for(i = 0 ; i < channels ; i++){
140cabdff1aSopenharmony_ci        ptr = &data[i];
141cabdff1aSopenharmony_ci        mono = pcm[i] ;
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci        for(j = 0 ; j < samples ; j++) {
144cabdff1aSopenharmony_ci            *ptr = av_clip_int16(mono[j] * 32767.f);
145cabdff1aSopenharmony_ci            ptr += channels;
146cabdff1aSopenharmony_ci        }
147cabdff1aSopenharmony_ci    }
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci    return 0 ;
150cabdff1aSopenharmony_ci}
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_cistatic int oggvorbis_decode_frame(AVCodecContext *avccontext, AVFrame *frame,
153cabdff1aSopenharmony_ci                                  int *got_frame_ptr, AVPacket *avpkt)
154cabdff1aSopenharmony_ci{
155cabdff1aSopenharmony_ci    OggVorbisDecContext *context = avccontext->priv_data ;
156cabdff1aSopenharmony_ci    float **pcm ;
157cabdff1aSopenharmony_ci    ogg_packet *op= &context->op;
158cabdff1aSopenharmony_ci    int samples, total_samples, total_bytes;
159cabdff1aSopenharmony_ci    int ret;
160cabdff1aSopenharmony_ci    int16_t *output;
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci    if(!avpkt->size){
163cabdff1aSopenharmony_ci    //FIXME flush
164cabdff1aSopenharmony_ci        return 0;
165cabdff1aSopenharmony_ci    }
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    frame->nb_samples = 8192*4;
168cabdff1aSopenharmony_ci    if ((ret = ff_get_buffer(avccontext, frame, 0)) < 0)
169cabdff1aSopenharmony_ci        return ret;
170cabdff1aSopenharmony_ci    output = (int16_t *)frame->data[0];
171cabdff1aSopenharmony_ci
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci    op->packet = avpkt->data;
174cabdff1aSopenharmony_ci    op->bytes  = avpkt->size;
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci//    av_log(avccontext, AV_LOG_DEBUG, "%d %d %d %"PRId64" %"PRId64" %d %d\n", op->bytes, op->b_o_s, op->e_o_s, op->granulepos, op->packetno, buf_size, context->vi.rate);
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci/*    for(i=0; i<op->bytes; i++)
179cabdff1aSopenharmony_ci      av_log(avccontext, AV_LOG_DEBUG, "%02X ", op->packet[i]);
180cabdff1aSopenharmony_ci    av_log(avccontext, AV_LOG_DEBUG, "\n");*/
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    if(vorbis_synthesis(&context->vb, op) == 0)
183cabdff1aSopenharmony_ci        vorbis_synthesis_blockin(&context->vd, &context->vb) ;
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci    total_samples = 0 ;
186cabdff1aSopenharmony_ci    total_bytes = 0 ;
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_ci    while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) {
189cabdff1aSopenharmony_ci        conv(samples, pcm, (char*)output + total_bytes, context->vi.channels) ;
190cabdff1aSopenharmony_ci        total_bytes += samples * 2 * context->vi.channels ;
191cabdff1aSopenharmony_ci        total_samples += samples ;
192cabdff1aSopenharmony_ci        vorbis_synthesis_read(&context->vd, samples) ;
193cabdff1aSopenharmony_ci    }
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    frame->nb_samples = total_samples;
196cabdff1aSopenharmony_ci    *got_frame_ptr   = total_samples > 0;
197cabdff1aSopenharmony_ci    return avpkt->size;
198cabdff1aSopenharmony_ci}
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic int oggvorbis_decode_close(AVCodecContext *avccontext) {
202cabdff1aSopenharmony_ci    OggVorbisDecContext *context = avccontext->priv_data ;
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci    vorbis_block_clear(&context->vb);
205cabdff1aSopenharmony_ci    vorbis_dsp_clear(&context->vd);
206cabdff1aSopenharmony_ci    vorbis_info_clear(&context->vi) ;
207cabdff1aSopenharmony_ci    vorbis_comment_clear(&context->vc) ;
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    return 0 ;
210cabdff1aSopenharmony_ci}
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ciconst FFCodec ff_libvorbis_decoder = {
214cabdff1aSopenharmony_ci    .p.name         = "libvorbis",
215cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("libvorbis"),
216cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_AUDIO,
217cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_VORBIS,
218cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_CHANNEL_CONF,
219cabdff1aSopenharmony_ci    .priv_data_size = sizeof(OggVorbisDecContext),
220cabdff1aSopenharmony_ci    .init           = oggvorbis_decode_init,
221cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(oggvorbis_decode_frame),
222cabdff1aSopenharmony_ci    .close          = oggvorbis_decode_close,
223cabdff1aSopenharmony_ci};
224